pax_global_header00006660000000000000000000000064140770455720014525gustar00rootroot0000000000000052 comment=a86e9fcd3a0c8f0ff2a8df431e69f9de97a26142 calcium-0.4.1/000077500000000000000000000000001407704557200131445ustar00rootroot00000000000000calcium-0.4.1/.binder/000077500000000000000000000000001407704557200144655ustar00rootroot00000000000000calcium-0.4.1/.binder/environment.yml000066400000000000000000000002151407704557200175520ustar00rootroot00000000000000name: calcium channels: - conda-forge - nodefaults dependencies: - gmp - mpfr - arb - libflint - antic - python - notebook calcium-0.4.1/.binder/postBuild000066400000000000000000000007361407704557200163630ustar00rootroot00000000000000#!/bin/bash set -e export LDFLAGS="-Wl,-rpath,${NB_PYTHON_PREFIX}/lib -L${NB_PYTHON_PREFIX}/lib" ./configure \ --prefix=${NB_PYTHON_PREFIX} \ --with-gmp=${NB_PYTHON_PREFIX} \ --with-mpfr=${NB_PYTHON_PREFIX} \ --with-flint=${NB_PYTHON_PREFIX} \ --with-arb=${NB_PYTHON_PREFIX} \ --with-antic=${NB_PYTHON_PREFIX} make -j4 make install ln -s $PWD/pycalcium/pyca.py $(${NB_PYTHON_PREFIX}/bin/python -c 'import site; print(site.getsitepackages()[0])')/pyca.py calcium-0.4.1/.gitignore000066400000000000000000000002061407704557200151320ustar00rootroot00000000000000Makefile build/* libcalcium.so* libcalcium.a doc/build/* doc/.ipynb_checkpoints/* *.ppm *.lo *.deps/ *.libs/ *.dirstamp *__pycache__* calcium-0.4.1/LICENSE000066400000000000000000000636421407704557200141640ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [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 Street, 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! calcium-0.4.1/Makefile.in000066400000000000000000000233461407704557200152210ustar00rootroot00000000000000ifdef $(DLPATH) $(DLPATH):=$($(DLPATH)):$(DLPATH_ADD) else $(DLPATH):=$(DLPATH_ADD) endif LIBDIR=lib QUIET_CC = @echo ' ' CC ' ' $@; QUIET_CXX = @echo ' ' CXX ' ' $@; QUIET_AR = @echo ' ' AR ' ' $@; AT=@ BUILD_DIRS = calcium utils_flint fmpz_mpoly_q fexpr fexpr_builtin qqbar ca ca_ext ca_field ca_vec ca_poly ca_mat $(EXTRA_BUILD_DIRS) TEMPLATE_DIRS = export SOURCES = LIB_SOURCES = $(wildcard $(patsubst %, %/*.c, $(BUILD_DIRS))) $(patsubst %, %/*.c, $(TEMPLATE_DIRS)) HEADERS = $(patsubst %, %.h, $(BUILD_DIRS)) OBJS = $(patsubst %.c, build/%.o, $(SOURCES)) LIB_OBJS = $(patsubst %, build/%/*.o, $(BUILD_DIRS)) LOBJS = $(patsubst %.c, build/%.lo, $(SOURCES)) LIB_LOBJS = $(patsubst %, build/%/*.lo, $(BUILD_DIRS)) MOD_LOBJS = $(patsubst %, build/%.lo, $(BUILD_DIRS)) EXMP_SOURCES = $(wildcard examples/*.c) EXMPS = $(patsubst %.c, %, $(EXMP_SOURCES)) TEST_SOURCES = $(wildcard test/*.c) TESTS = $(patsubst %.c, build/%$(EXEEXT), $(TEST_SOURCES)) PROF_SOURCES = $(wildcard profile/*.c) PROFS = $(patsubst %.c, %$(EXEEXT), $(PROF_SOURCES)) TUNE_SOURCES = $(wildcard tune/*.c) TUNE = $(patsubst %.c, %$(EXEEXT), $(TUNE_SOURCES)) EXT_SOURCES = $(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), $(wildcard $(ext)/$(dir)/*.c))) EXT_TEST_SOURCES = $(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), $(wildcard $(ext)/$(dir)/test/t-*.c))) EXT_TUNE_SOURCES = $(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), $(wildcard $(ext)/$(dir)/tune/*.c))) EXT_PROF_SOURCES = $(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), $(wildcard $(ext)/$(dir)/profile/p-*.c))) EXT_OBJS = $(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), build/$(dir).lo)) EXT_HEADERS = $(foreach ext, $(EXTENSIONS), $(wildcard $(ext)/*.h)) all: library quiet: library verbose: $(MAKE) AT= QUIET_CC= QUIET_CXX= QUIET_AR= clean: $(AT)$(foreach dir, $(BUILD_DIRS), BUILD_DIR=../build/$(dir); export BUILD_DIR; MOD_DIR=$(dir); export MOD_DIR; $(MAKE) -f ../Makefile.subdirs -C $(dir) clean || exit $$?;) $(AT)$(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), BUILD_DIR=$(CURDIR)/build/$(dir); export BUILD_DIR; MOD_DIR=$(dir); export MOD_DIR; $(MAKE) -f $(CURDIR)/Makefile.subdirs -C $(ext)/$(dir) clean || exit $$?;)) rm -f $(OBJS) $(LOBJS) $(TESTS) $(PROFS) $(EXMPS) $(wildcard $(CALCIUM_LIBNAME)*) libcalcium.a rm -rf build distclean: clean rm -f Makefile profile: library $(PROF_SOURCES) $(EXT_PROF_SOURCES) build/profiler.o mkdir -p build/profile ifndef MOD $(AT)$(foreach prog, $(PROFS), $(CC) $(ABI_FLAG) -std=c99 -O2 -g $(INCS) $(prog).c build/profiler.o -o build/$(prog) $(LIBS) || exit $$?;) $(AT)$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir)/profile; BUILD_DIR=../build/$(dir); export BUILD_DIR; $(MAKE) -f ../Makefile.subdirs -C $(dir) profile || exit $$?;) $(AT)$(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), mkdir -p build/$(dir)/profile; BUILD_DIR=$(CURDIR)/build/$(dir); export BUILD_DIR; MOD_DIR=$(dir); export MOD_DIR; $(MAKE) -f $(CURDIR)/Makefile.subdirs -C $(ext)/$(dir) profile || exit $$?;)) else $(AT)$(foreach dir, $(MOD), mkdir -p build/$(dir)/profile; BUILD_DIR=../build/$(dir); export BUILD_DIR; $(MAKE) -f ../Makefile.subdirs -C $(dir) profile || exit $$?;) endif tune: library $(TUNE_SOURCES) $(EXT_TUNE_SOURCES) mkdir -p build/tune $(AT)$(foreach prog, $(TUNE), $(CC) $(CFLAGS) $(INCS) $(prog).c -o build/$(prog) $(LIBS) || exit $$?;) $(AT)$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir)/tune; BUILD_DIR=../build/$(dir); export BUILD_DIR; $(MAKE) -f ../Makefile.subdirs -C $(dir) tune || exit $$?;) $(AT)$(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), mkdir -p build/$(dir)/tune; BUILD_DIR=$(CURDIR)/build/$(dir); export BUILD_DIR; MOD_DIR=$(dir); export MOD_DIR; $(MAKE) -f $(CURDIR)/Makefile.subdirs -C $(ext)/$(dir) tune || exit $$?;)) examples: library $(EXMP_SOURCES) mkdir -p build/examples $(AT)$(foreach prog, $(EXMPS), $(CC) $(CFLAGS) $(INCS) $(prog).c -o build/$(prog) $(LIBS) || exit $$?;) $(CALCIUM_LIB): $(LOBJS) $(LIB_SOURCES) $(EXT_SOURCES) $(HEADERS) $(EXT_HEADERS) | build build/interfaces $(AT)$(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), mkdir -p build/$(dir); BUILD_DIR=$(CURDIR)/build/$(dir); export BUILD_DIR; MOD_DIR=$(dir); export MOD_DIR; $(MAKE) -f $(CURDIR)/Makefile.subdirs -C $(ext)/$(dir) shared || exit $$?;)) $(AT)$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir); BUILD_DIR=../build/$(dir); export BUILD_DIR; MOD_DIR=$(dir); export MOD_DIR; $(MAKE) -f ../Makefile.subdirs -C $(dir) shared || exit $$?;) $(CC) $(ABI_FLAG) -shared $(EXTRA_SHARED_FLAGS) $(LOBJS) $(MOD_LOBJS) $(EXT_OBJS) -o $(CALCIUM_LIB) $(LDFLAGS) $(LIBS2); -$(AT)if [ "$(CALCIUM_SOLIB)" -eq "1" ]; then \ $(LDCONFIG) -n "$(CURDIR)"; \ fi ln -sf "$(CALCIUM_LIB)" "$(CALCIUM_LIBNAME)"; \ ln -sf "$(CALCIUM_LIB)" "$(CALCIUM_LIBNAME).$(CALCIUM_MAJOR)"; \ libcalcium.a: $(OBJS) $(LIB_SOURCES) $(EXT_SOURCES) $(HEADERS) $(EXT_HEADERS) | build build/interfaces $(AT)$(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), mkdir -p build/$(dir); BUILD_DIR=$(CURDIR)/build/$(dir); export BUILD_DIR; MOD_DIR=$(dir); export MOD_DIR; $(MAKE) -f $(CURDIR)/Makefile.subdirs -C $(ext)/$(dir) static || exit $$?;)) $(AT)$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir); BUILD_DIR=../build/$(dir); export BUILD_DIR; MOD_DIR=$(dir); export MOD_DIR; $(MAKE) -f ../Makefile.subdirs -C $(dir) static || exit $$?;) $(AT)if [ "$(CALCIUM_SHARED)" -eq "0" ]; then \ touch test/t-*.c; \ $(foreach dir, $(BUILD_DIRS), touch $(dir)/test/t-*.c;) \ $(foreach ext, $(EXTENSIONS), $(foreach mod, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), touch $(ext)/$(mod)/test/t-*.c;)) \ fi $(AT)$(foreach mod, $(BUILD_DIRS), $(AR) rcs libcalcium.a build/$(mod)/*.o || exit $$?;) $(AT)$(foreach ext, $(EXTENSIONS), $(foreach mod, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), $(AR) rcs libcalcium.a build/$(mod)/*.o || exit $$?;)) library: $(AT)if [ "$(CALCIUM_SHARED)" -eq "1" ]; then \ $(MAKE) shared; \ fi $(AT)if [ "$(CALCIUM_STATIC)" -eq "1" ]; then \ $(MAKE) static; \ fi shared: $(CALCIUM_LIB) static: libcalcium.a tests: library $(TESTS) $(AT)$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir)/test; BUILD_DIR=../build/$(dir); export BUILD_DIR; $(MAKE) -f ../Makefile.subdirs -C $(dir) tests || exit $$?;) $(AT)$(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), mkdir -p build/$(dir)/test; BUILD_DIR=$(CURDIR)/build/$(dir); export BUILD_DIR; MOD_DIR=$(dir); export MOD_DIR; $(MAKE) -f $(CURDIR)/Makefile.subdirs -C $(ext)/$(dir) tests || exit $$?;)) mkdir -p build/interfaces/test check: library ifndef MOD python3 pycalcium/pyca.py $(AT)$(MAKE) $(TESTS) $(AT)$(foreach prog, $(TESTS), $(prog) || exit $$?;) $(AT)$(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), mkdir -p build/$(dir)/test; BUILD_DIR=$(CURDIR)/build/$(dir); export BUILD_DIR; MOD_DIR=$(dir); export MOD_DIR; $(MAKE) -f $(CURDIR)/Makefile.subdirs -C $(ext)/$(dir) check || exit $$?;)) $(AT)$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir)/test; BUILD_DIR=../build/$(dir); export BUILD_DIR; $(MAKE) -f ../Makefile.subdirs -C $(dir) check || exit $$?;) mkdir -p build/interfaces/test else $(AT)$(foreach dir, $(MOD), test ! -d $(dir) || mkdir -p build/$(dir)/test; BUILD_DIR=../build/$(dir); export BUILD_DIR; test ! -d $(dir) || $(MAKE) -f ../Makefile.subdirs -C $(dir) check || exit $$?;) $(AT)$(foreach ext, $(EXTENSIONS), $(AT)$(foreach dir, $(MOD), MOD_DIR=$(dir); export MOD_DIR; test ! -d $(ext)/$(dir) || mkdir -p build/$(dir)/test; BUILD_DIR=$(CURDIR)/build/$(dir); export BUILD_DIR; test ! -d $(ext)/$(dir) || $(MAKE) -f $(CURDIR)/Makefile.subdirs -C $(ext)/$(dir) check || exit $$?;)) endif valgrind: library ifndef MOD $(AT)$(foreach dir, $(BUILD_DIRS), mkdir -p build/$(dir)/test; BUILD_DIR=../build/$(dir); export BUILD_DIR; $(MAKE) -f ../Makefile.subdirs -C $(dir) valgrind || exit $$?;) $(AT)$(foreach ext, $(EXTENSIONS), $(foreach dir, $(patsubst $(ext)/%.h, %, $(wildcard $(ext)/*.h)), mkdir -p build/$(dir)/test; BUILD_DIR=$(CURDIR)/build/$(dir); export BUILD_DIR; MOD_DIR=$(dir); export MOD_DIR; $(MAKE) -f $(CURDIR)/Makefile.subdirs -C $(ext)/$(dir) valgrind || exit $$?;)) else $(AT)$(foreach dir, $(MOD), mkdir -p build/$(dir)/test; BUILD_DIR=../build/$(dir); export BUILD_DIR; $(MAKE) -f ../Makefile.subdirs -C $(dir) valgrind || exit $$?;) endif install: library mkdir -p $(DESTDIR)$(PREFIX)/$(LIBDIR) mkdir -p $(DESTDIR)$(PREFIX)/include/calcium $(AT)if [ "$(CALCIUM_SHARED)" -eq "1" ]; then \ cp $(CALCIUM_LIB) "$(DESTDIR)$(PREFIX)/$(LIBDIR)"; \ cp -a $(shell ls $(CALCIUM_LIBNAME)*) "$(DESTDIR)$(PREFIX)/$(LIBDIR)"; \ fi $(AT)if [ "$(CALCIUM_STATIC)" -eq "1" ]; then \ cp libcalcium.a $(DESTDIR)$(PREFIX)/$(LIBDIR); \ fi cp $(HEADERS) $(DESTDIR)$(PREFIX)/include/calcium $(AT)if [ ! -z $(EXT_HEADERS) ]; then \ cp $(EXT_HEADERS) $(DESTDIR)$(PREFIX)/include/calcium; \ fi build: mkdir -p build build/%.lo: %.c $(HEADERS) | build $(QUIET_CC) $(CC) $(PIC_FLAG) $(CFLAGS) $(INCS) -c $< -o $@; build/%.o: %.c $(HEADERS) | build $(QUIET_CC) $(CC) $(CFLAGS) $(INCS) -c $< -o $@; build/test/%$(EXEEXT): test/%.c $(HEADERS) | build/test $(QUIET_CC) $(CC) $(CFLAGS) $(INCS) $< -o $@ $(LIBS) build/test: mkdir -p build/test build/interfaces: mkdir -p build/interfaces print-%: @echo '$*=$($*)' .PHONY: profile library shared static clean examples tune check tests distclean dist install all valgrind calcium-0.4.1/Makefile.subdirs000066400000000000000000000047641407704557200162710ustar00rootroot00000000000000QUIET_CC = @echo ' ' CC ' ' $@; AT=@ SOURCES = $(wildcard *.c) HEADERS = $(wildcard ../*.h) TEST_HEADERS = $(wildcard *.h) OBJS = $(patsubst %.c, $(BUILD_DIR)/$(MOD_DIR)_%.o, $(SOURCES)) LOBJS = $(patsubst %.c, $(BUILD_DIR)/%.lo, $(SOURCES)) MOD_LOBJ = $(BUILD_DIR)/../$(MOD_DIR).lo TEST_SOURCES = $(wildcard test/*.c) TESTXX_SOURCES = $(wildcard test/*.cpp) PROF_SOURCES = $(wildcard profile/*.c) TUNE_SOURCES = $(wildcard tune/*.c) TESTS = $(patsubst %.c, $(BUILD_DIR)/%$(EXEEXT), $(TEST_SOURCES)) \ $(patsubst %.cpp, $(BUILD_DIR)/%$(EXEEXT), $(TESTXX_SOURCES)) TESTS_RUN = $(patsubst %, %_RUN, $(TESTS)) VALGRIND_RUN = $(patsubst %, %_VALGRIND_RUN, $(TESTS)) PROFS = $(patsubst %.c, $(BUILD_DIR)/%$(EXEEXT), $(PROF_SOURCES)) TUNE = $(patsubst %.c, %$(EXEEXT), $(TUNE_SOURCES)) all: shared static shared: $(MOD_LOBJ) static: $(OBJS) profile: $(PROFS) -include $(patsubst %, %.d, $(PROFS)) $(BUILD_DIR)/profile/%$(EXEEXT): profile/%.c $(BUILD_DIR)/../profiler.o $(QUIET_CC) $(CC) $(ABI_FLAG) -O2 -std=c99 -g $(INCS) $< $(BUILD_DIR)/../profiler.o -o $@ $(LDLFAGS) $(LIBS) -MMD -MP -MF $@.d -MT "$@" -MT "$@.d" tune: $(TUNE_SOURCES) $(HEADERS) $(AT)$(foreach prog, $(TUNE), $(CC) $(CFLAGS) $(INCS) $(prog).c -o $(BUILD_DIR)/$(prog) $(LDLFAGS) $(LIBS) || exit $$?;) -include $(OBJS:.o=.d) $(BUILD_DIR)/$(MOD_DIR)_%.o: %.c $(QUIET_CC) $(CC) $(CFLAGS) $(INCS) -c $< -o $@ -MMD -MP -MF "$(BUILD_DIR)/$(MOD_DIR)_$*.d" -MT "$(BUILD_DIR)/$(MOD_DIR)_$*.d" -MT "$@" $(MOD_LOBJ): $(LOBJS) $(QUIET_CC) $(CC) $(ABI_FLAG) -r $^ -o $@ -nostdlib -include $(LOBJS:.lo=.d) $(BUILD_DIR)/%.lo: %.c $(QUIET_CC) $(CC) $(PIC_FLAG) $(CFLAGS) $(INCS) -c $< -o $@ -MMD -MP -MF "$(BUILD_DIR)/$*.d" -MT "$(BUILD_DIR)/$*.d" -MT "$@" clean: rm -rf $(BUILD_DIR) $(MOD_LOBJ) tests: $(TESTS) check: tests $(TESTS_RUN) valgrind: tests $(VALGRIND_RUN) -include $(patsubst %, %.d, $(TESTS)) ifeq ($(ARB_SHARED), 0) $(BUILD_DIR)/test/%$(EXEEXT): $(BUILD_DIR)/../../libarb.a endif $(BUILD_DIR)/test/%$(EXEEXT): test/%.c $(QUIET_CC) $(CC) $(CFLAGS) $(INCS) $< -o $@ $(LDLFAGS) $(LIBS) -MMD -MP -MF $@.d -MT "$@" -MT "$@.d" $(BUILD_DIR)/test/%$(EXEEXT): test/%.cpp $(BUILD_DIR)/../../test_helpers.o $(QUIET_CC) $(CXX) $(CFLAGS) $(INCS) $< -o $@ $(LDLFAGS) $(LIBS) -MMD -MP -MF $@.d -MT "$@" -MT "$@.d" %_RUN: % @time -f "%e" $< %_VALGRIND_RUN: % valgrind --track-origins=yes --leak-check=full --show-reachable=yes --log-file="$*.valgrind" $< .PHONY: profile tune clean check tests all shared static valgrind %_RUN %_VALGRIND_RUN calcium-0.4.1/README.md000066400000000000000000000024211407704557200144220ustar00rootroot00000000000000# Calcium Calcium (pronounced “kalkium”) is a C library for exact computation with real and complex numbers, presently in early development. ![calcium logo](http://fredrikj.net/calcium/_images/ca2.svg) Documentation: http://fredrikj.net/calcium/ Try Online: [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/fredrik-johansson/calcium/HEAD?filepath=doc%2Fintroduction.ipynb) Author: Fredrik Johansson Features: * Exact real and complex numbers represented as elements of automatically extended multivariate fields * Support for algebraic, transcendental and mixed fields * Automatic, rigorous numerical embeddings and arbitrary-precision numerical evaluation (on top of Arb) * Efficient field arithmetic (on top of Flint and Antic) * Automatic, rigorous simplification (using integer relations, ideal reduction, and other methods) * Complete decision procedures for algebraic numbers * Partial decision procedures for transcendental numbers * Polynomials and matrices with exact coefficients * Exact real and complex algebraic numbers (absolute minpoly representation) * Multivariate rational functions (on top of Flint) * Gröbner basis computation (on top of Flint) * Symbolic expressions (conversions, evaluation, LaTeX output) calcium-0.4.1/ca.h000066400000000000000000000535151407704557200137110ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef CA_H #define CA_H #ifdef CA_INLINES_C #define CA_INLINE #else #define CA_INLINE static __inline__ #endif #include #include "flint/flint.h" #include "antic/nf.h" #include "antic/nf_elem.h" #include "calcium.h" #include "qqbar.h" #include "fmpz_mpoly_q.h" #include "utils_flint.h" #include "fexpr.h" #ifdef __cplusplus extern "C" { #endif #define CA_INFO(ctx, args) do { if (ctx->options[CA_OPT_VERBOSE]) \ do { flint_printf("%s:%d: ", __FILE__, __LINE__); flint_printf args; } \ while (0); } while (0); /* Number object *************************************************************/ typedef union { fmpq q; /* rational number */ nf_elem_struct nf; /* algebraic number field element */ fmpz_mpoly_q_struct * mpoly_q; /* generic field element */ } ca_elem_struct; typedef struct { ulong field; ca_elem_struct elem; } ca_struct; typedef ca_struct ca_t[1]; typedef ca_struct * ca_ptr; typedef const ca_struct * ca_srcptr; #define CA_FMPQ(x) (&((x)->elem.q)) #define CA_MPOLY_Q(x) (&(((x)->elem.mpoly_q)[0])) #define CA_NF_ELEM(x) (&((x)->elem.nf)) #define CA_FMPQ_NUMREF(x) (fmpq_numref(CA_FMPQ(x))) #define CA_FMPQ_DENREF(x) (fmpq_denref(CA_FMPQ(x))) #define CA_FIELD(x, ctx) ((ca_field_ptr) ((x)->field)) #define CA_FIELD_ULONG(x) ((x)->field) /* We always allocate QQ and QQ(i) */ #define CA_IS_QQ(x, ctx) (CA_FIELD(x, ctx) == (ctx)->field_qq) #define CA_IS_QQ_I(x, ctx) (CA_FIELD(x, ctx) == (ctx)->field_qq_i) /* Use the low two bits of the field pointer to encode special values. */ /* The field pointer with the mask removed is NULL for Unknown/Undefined/Uinf, and a normal field pointer for signed infinity (encoding the sign). */ #define CA_UNKNOWN UWORD(1) #define CA_UNDEFINED UWORD(2) #define CA_INF UWORD(3) #define CA_SPECIAL (CA_UNKNOWN | CA_UNDEFINED | CA_INF) #define CA_IS_SPECIAL(x) (CA_FIELD_ULONG(x) & CA_SPECIAL) #define CA_IS_UNKNOWN(x) (CA_FIELD_ULONG(x) == CA_UNKNOWN) #define CA_IS_UNDEFINED(x) (CA_FIELD_ULONG(x) == CA_UNDEFINED) #define CA_IS_INF(x) ((CA_FIELD_ULONG(x) & CA_SPECIAL) == CA_INF) #define CA_IS_UNSIGNED_INF(x) (CA_FIELD_ULONG(x) == CA_INF) #define CA_IS_SIGNED_INF(x) (CA_IS_INF(x) && !CA_IS_UNSIGNED_INF(x)) #define CA_FIELD_UNSPECIAL(x, ctx) ((ca_field_ptr) (CA_FIELD_ULONG(x) & ~CA_SPECIAL)) /* Extension object **********************************************************/ typedef struct { qqbar_struct x; /* qqbar_t element */ nf_struct * nf; /* antic number field for fast arithmetic */ } ca_ext_qqbar; typedef struct { ca_struct * args; /* Function arguments x1, ..., xn. */ slong nargs; /* Number of function arguments n. */ acb_struct enclosure; /* Cached numerical enclosure of f(x1,...,xn) */ slong prec; /* Working precision of cached enclosure */ qqbar_struct * qqbar; /* Cached qqbar */ } ca_ext_func_data; typedef struct { calcium_func_code head; /* f = F_Pi, F_Exp, ... */ ulong hash; slong depth; union { ca_ext_qqbar qqbar; ca_ext_func_data func_data; } data; } ca_ext_struct; typedef ca_ext_struct ca_ext_t[1]; typedef ca_ext_struct * ca_ext_ptr; typedef const ca_ext_struct * ca_ext_srcptr; #define CA_EXT_HEAD(x) ((x)->head) #define CA_EXT_HASH(x) ((x)->hash) #define CA_EXT_DEPTH(x) ((x)->depth) #define CA_EXT_IS_QQBAR(x) ((x)->head == CA_QQBar) #define CA_EXT_QQBAR(_x) (&((_x)->data.qqbar.x)) #define CA_EXT_QQBAR_NF(_x) ((_x)->data.qqbar.nf) #define CA_EXT_FUNC_ARGS(x) ((x)->data.func_data.args) #define CA_EXT_FUNC_NARGS(x) ((x)->data.func_data.nargs) #define CA_EXT_FUNC_ENCLOSURE(x) (&((x)->data.func_data.enclosure)) #define CA_EXT_FUNC_PREC(x) ((x)->data.func_data.prec) typedef struct { ca_ext_struct ** items; slong length; slong alloc; slong hash_size; slong * hash_table; } ca_ext_cache_struct; typedef ca_ext_cache_struct ca_ext_cache_t[1]; /* Field object **************************************************************/ typedef struct { slong length; /* Number of generators */ ca_ext_struct ** ext; /* Generators */ fmpz_mpoly_vec_struct ideal; /* Algebraic relations for reduction */ ulong hash; } ca_field_struct; typedef ca_field_struct ca_field_t[1]; typedef ca_field_struct * ca_field_ptr; typedef const ca_field_struct * ca_field_srcptr; #define CA_FIELD_LENGTH(K) ((K)->length) #define CA_FIELD_EXT(K) ((K)->ext) #define CA_FIELD_EXT_ELEM(K, i) ((K)->ext[i]) #define CA_FIELD_HASH(K) ((K)->hash) #define CA_FIELD_IS_QQ(K) ((K)->length == 0) #define CA_FIELD_IS_NF(K) ((K)->ideal.length == -1) #define CA_FIELD_IS_GENERIC(K) (!CA_FIELD_IS_QQ(K) && !CA_FIELD_IS_NF(K)) #define CA_FIELD_NF(K) (((K)->ext[0]->data.qqbar.nf)) #define CA_FIELD_NF_QQBAR(K) (&((K)->ext[0]->data.qqbar.x)) #define CA_FIELD_IDEAL(K) (&((K)->ideal)) #define CA_FIELD_IDEAL_ELEM(K, i) fmpz_mpoly_vec_entry(CA_FIELD_IDEAL(K), i) #define CA_FIELD_IDEAL_LENGTH(K) ((K)->ideal.length) #define CA_FIELD_IDEAL_ALLOC(K) ((K)->ideal.alloc) #define CA_FIELD_IDEAL_P(K) ((K)->ideal.p) #define CA_MCTX_1(ctx) ((ctx)->mctx[0]) #define CA_FIELD_MCTX(K, ctx) ((ctx)->mctx[CA_FIELD_LENGTH(K) - 1]) typedef struct { ca_field_struct ** items; slong length; slong alloc; slong hash_size; slong * hash_table; } ca_field_cache_struct; typedef ca_field_cache_struct ca_field_cache_t[1]; /* Context object ************************************************************/ enum { CA_OPT_VERBOSE, CA_OPT_PRINT_FLAGS, CA_OPT_MPOLY_ORD, CA_OPT_PREC_LIMIT, CA_OPT_QQBAR_DEG_LIMIT, CA_OPT_LOW_PREC, CA_OPT_SMOOTH_LIMIT, CA_OPT_LLL_PREC, CA_OPT_POW_LIMIT, CA_OPT_USE_GROEBNER, CA_OPT_GROEBNER_LENGTH_LIMIT, CA_OPT_GROEBNER_POLY_LENGTH_LIMIT, CA_OPT_GROEBNER_POLY_BITS_LIMIT, CA_OPT_VIETA_LIMIT, CA_OPT_TRIG_FORM, CA_OPT_NUM_OPTIONS }; #define CA_TRIG_DIRECT 0 #define CA_TRIG_EXPONENTIAL 1 #define CA_TRIG_SINE_COSINE 2 #define CA_TRIG_TANGENT 3 typedef struct { ca_ext_cache_struct ext_cache; /* Cached extension objects */ ca_field_cache_struct field_cache; /* Cached extension fields */ ca_field_struct * field_qq; /* Quick access to QQ */ ca_field_struct * field_qq_i; /* Quick access to QQ(i) */ fmpz_mpoly_ctx_struct ** mctx; /* Cached contexts for multivariate polys */ slong mctx_len; slong * options; } ca_ctx_struct; typedef ca_ctx_struct ca_ctx_t[1]; #define CA_CTX_EXT_CACHE(ctx) (&((ctx)->ext_cache)) #define CA_CTX_FIELD_CACHE(ctx) (&((ctx)->field_cache)) #define CA_CTX_FIELD_WITH_INDEX(ctx, i) ((&((ctx)->field_cache))->items[i]) /* Context management */ void ca_ctx_init(ca_ctx_t ctx); void ca_ctx_clear(ca_ctx_t ctx); void ca_ctx_print(ca_ctx_t ctx); CA_INLINE slong ca_ctx_get_option(ca_ctx_t ctx, slong i) { return ctx->options[i]; } CA_INLINE void ca_ctx_set_option(ca_ctx_t ctx, slong i, slong value) { ctx->options[i] = value; } ca_field_ptr _ca_ctx_get_field_const(ca_ctx_t ctx, calcium_func_code func); ca_field_ptr _ca_ctx_get_field_fx(ca_ctx_t ctx, calcium_func_code func, const ca_t x); ca_field_ptr _ca_ctx_get_field_fxy(ca_ctx_t ctx, calcium_func_code func, const ca_t x, const ca_t y); /* Numbers */ void ca_init(ca_t x, ca_ctx_t ctx); void ca_clear(ca_t x, ca_ctx_t ctx); void ca_swap(ca_t x, ca_t y, ca_ctx_t ctx); void _ca_make_field_element(ca_t x, ca_field_srcptr field, ca_ctx_t ctx); CA_INLINE void _ca_make_fmpq(ca_t x, ca_ctx_t ctx) { if (!CA_IS_QQ(x, ctx)) _ca_make_field_element(x, ctx->field_qq, ctx); } CA_INLINE void _ca_function_fx(ca_t res, calcium_func_code func, const ca_t x, ca_ctx_t ctx) { ca_field_srcptr field = _ca_ctx_get_field_fx(ctx, func, x); _ca_make_field_element(res, field, ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_FIELD_MCTX(field, ctx)); } CA_INLINE void _ca_function_fxy(ca_t res, calcium_func_code func, const ca_t x, const ca_t y, ca_ctx_t ctx) { ca_field_srcptr field = _ca_ctx_get_field_fxy(ctx, func, x, y); _ca_make_field_element(res, field, ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_FIELD_MCTX(field, ctx)); } void ca_set(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_transfer(ca_t res, ca_ctx_t res_ctx, const ca_t src, ca_ctx_t src_ctx); void ca_zero(ca_t x, ca_ctx_t ctx); void ca_one(ca_t x, ca_ctx_t ctx); void ca_neg_one(ca_t x, ca_ctx_t ctx); void ca_set_si(ca_t x, slong v, ca_ctx_t ctx); void ca_set_ui(ca_t x, ulong v, ca_ctx_t ctx); void ca_set_fmpz(ca_t x, const fmpz_t v, ca_ctx_t ctx); void ca_set_fmpq(ca_t x, const fmpq_t v, ca_ctx_t ctx); void ca_set_d(ca_t res, double x, ca_ctx_t ctx); void ca_set_d_d(ca_t res, double x, double y, ca_ctx_t ctx); void ca_i(ca_t x, ca_ctx_t ctx); void ca_neg_i(ca_t x, ca_ctx_t ctx); void ca_pi(ca_t res, ca_ctx_t ctx); void ca_pi_i(ca_t res, ca_ctx_t ctx); void ca_euler(ca_t res, ca_ctx_t ctx); void ca_unknown(ca_t x, ca_ctx_t ctx); void ca_undefined(ca_t x, ca_ctx_t ctx); void ca_uinf(ca_t x, ca_ctx_t ctx); void ca_pos_inf(ca_t x, ca_ctx_t ctx); void ca_neg_inf(ca_t x, ca_ctx_t ctx); void ca_pos_i_inf(ca_t x, ca_ctx_t ctx); void ca_neg_i_inf(ca_t x, ca_ctx_t ctx); void ca_set_qqbar(ca_t res, const qqbar_t x, ca_ctx_t ctx); int ca_can_evaluate_qqbar(const ca_t x, ca_ctx_t ctx); int ca_get_qqbar(qqbar_t res, const ca_t x, ca_ctx_t ctx); int ca_get_fmpq(fmpq_t res, const ca_t x, ca_ctx_t ctx); int ca_get_fmpz(fmpz_t res, const ca_t x, ca_ctx_t ctx); /* Symbolic expressions */ #define CA_FEXPR_SERIALIZATION 1 void ca_get_fexpr(fexpr_t res, const ca_t x, ulong flags, ca_ctx_t ctx); int ca_set_fexpr(ca_t res, const fexpr_t expr, ca_ctx_t ctx); /* Printing */ #define CA_PRINT_N UWORD(1) #define CA_PRINT_REPR UWORD(2) #define CA_PRINT_FIELD UWORD(4) #define CA_PRINT_DIGITS UWORD(16) #define CA_PRINT_DEFAULT (CA_PRINT_N | CA_PRINT_REPR) #define CA_PRINT_DEBUG (CA_PRINT_N | CA_PRINT_REPR | CA_PRINT_FIELD) void ca_print(const ca_t x, ca_ctx_t ctx); void ca_fprint(FILE * fp, const ca_t x, ca_ctx_t ctx); void ca_printn(const ca_t x, slong n, ca_ctx_t ctx); char * ca_get_str(const ca_t x, ca_ctx_t ctx); /* Random generation */ void ca_randtest_same_nf(ca_t res, flint_rand_t state, const ca_t x, slong bits, slong den_bits, ca_ctx_t ctx); void ca_randtest_rational(ca_t res, flint_rand_t state, slong bits, ca_ctx_t ctx); void ca_randtest(ca_t res, flint_rand_t state, slong depth, slong bits, ca_ctx_t ctx); void ca_randtest_special(ca_t res, flint_rand_t state, slong depth, slong bits, ca_ctx_t ctx); /* Representation properties */ CA_INLINE int ca_is_special(const ca_t x, ca_ctx_t ctx) { return CA_IS_SPECIAL(x); } CA_INLINE int ca_is_unknown(const ca_t x, ca_ctx_t ctx) { return CA_IS_UNKNOWN(x); } CA_INLINE int ca_is_qq_elem(const ca_t x, ca_ctx_t ctx) { return CA_IS_QQ(x, ctx); } CA_INLINE int ca_is_qq_elem_zero(const ca_t x, ca_ctx_t ctx) { return CA_IS_QQ(x, ctx) && fmpq_is_zero(CA_FMPQ(x)); } CA_INLINE int ca_is_qq_elem_one(const ca_t x, ca_ctx_t ctx) { return CA_IS_QQ(x, ctx) && fmpq_is_one(CA_FMPQ(x)); } CA_INLINE int ca_is_qq_elem_integer(const ca_t x, ca_ctx_t ctx) { return CA_IS_QQ(x, ctx) && fmpz_is_one(CA_FMPQ_DENREF(x)); } CA_INLINE int ca_is_nf_elem(const ca_t x, ca_ctx_t ctx) { return !CA_IS_SPECIAL(x) && CA_FIELD_IS_NF(CA_FIELD(x, ctx)); } CA_INLINE int ca_is_generic_elem(const ca_t x, ca_ctx_t ctx) { return !CA_IS_SPECIAL(x) && CA_FIELD_IS_GENERIC(CA_FIELD(x, ctx)); } int ca_is_cyclotomic_nf_elem(slong * p, ulong * q, const ca_t x, ca_ctx_t ctx); /* Value predicates and comparisons */ truth_t ca_is_zero_check_fast(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_number(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_zero(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_one(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_neg_one(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_i(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_neg_i(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_algebraic(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_rational(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_integer(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_real(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_negative_real(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_imaginary(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_undefined(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_infinity(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_uinf(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_signed_inf(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_pos_inf(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_neg_inf(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_pos_i_inf(const ca_t x, ca_ctx_t ctx); truth_t ca_check_is_neg_i_inf(const ca_t x, ca_ctx_t ctx); truth_t ca_check_equal(const ca_t x, const ca_t y, ca_ctx_t ctx); truth_t ca_check_lt(const ca_t x, const ca_t y, ca_ctx_t ctx); truth_t ca_check_le(const ca_t x, const ca_t y, ca_ctx_t ctx); truth_t ca_check_gt(const ca_t x, const ca_t y, ca_ctx_t ctx); truth_t ca_check_ge(const ca_t x, const ca_t y, ca_ctx_t ctx); int ca_equal_repr(const ca_t x, const ca_t y, ca_ctx_t ctx); int ca_cmp_repr(const ca_t x, const ca_t y, ca_ctx_t ctx); ulong ca_hash_repr(const ca_t x, ca_ctx_t ctx); /* Field structure operations */ void ca_merge_fields(ca_t resx, ca_t resy, const ca_t x, const ca_t y, ca_ctx_t ctx); void ca_condense_field(ca_t res, ca_ctx_t ctx); ca_ext_ptr ca_is_gen_as_ext(const ca_t x, ca_ctx_t ctx); /* Arithmetic */ /* todo: document */ void _ca_mpoly_q_reduce_ideal(fmpz_mpoly_q_t res, ca_field_srcptr field, ca_ctx_t ctx); void _ca_mpoly_q_simplify_fraction_ideal(fmpz_mpoly_q_t res, ca_field_srcptr field, ca_ctx_t ctx); void ca_neg(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_add_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx); void ca_add_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx); void ca_add_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx); void ca_add_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx); void ca_add(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx); void ca_sub_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx); void ca_sub_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx); void ca_sub_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx); void ca_sub_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx); void ca_fmpq_sub(ca_t res, const fmpq_t x, const ca_t y, ca_ctx_t ctx); void ca_fmpz_sub(ca_t res, const fmpz_t x, const ca_t y, ca_ctx_t ctx); void ca_ui_sub(ca_t res, ulong x, const ca_t y, ca_ctx_t ctx); void ca_si_sub(ca_t res, slong x, const ca_t y, ca_ctx_t ctx); void ca_sub(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx); void ca_mul_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx); void ca_mul_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx); void ca_mul_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx); void ca_mul_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx); void ca_mul(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx); void ca_inv(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_fmpq_div(ca_t res, const fmpq_t x, const ca_t y, ca_ctx_t ctx); void ca_fmpz_div(ca_t res, const fmpz_t x, const ca_t y, ca_ctx_t ctx); void ca_ui_div(ca_t res, ulong x, const ca_t y, ca_ctx_t ctx); void ca_si_div(ca_t res, slong x, const ca_t y, ca_ctx_t ctx); void ca_div_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx); void ca_div_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx); void ca_div_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx); void ca_div_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx); void ca_div(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx); void ca_dot(ca_t res, const ca_t initial, int subtract, ca_srcptr x, slong xstep, ca_srcptr y, slong ystep, slong len, ca_ctx_t ctx); void ca_fmpz_poly_evaluate(ca_t res, const fmpz_poly_t poly, const ca_t x, ca_ctx_t ctx); void ca_fmpq_poly_evaluate(ca_t res, const fmpq_poly_t poly, const ca_t x, ca_ctx_t ctx); void ca_fmpz_mpoly_evaluate_horner(ca_t res, const fmpz_mpoly_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx); void ca_fmpz_mpoly_evaluate_iter(ca_t res, const fmpz_mpoly_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx); void ca_fmpz_mpoly_evaluate(ca_t res, const fmpz_mpoly_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx); void ca_fmpz_mpoly_q_evaluate(ca_t res, const fmpz_mpoly_q_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx); void ca_fmpz_mpoly_q_evaluate_no_division_by_zero(ca_t res, const fmpz_mpoly_q_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx); void ca_inv_no_division_by_zero(ca_t res, const ca_t x, ca_ctx_t ctx); /* Powers and roots */ CA_INLINE void ca_sqr(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_mul(res, x, x, ctx); } void ca_pow_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx); void ca_pow_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx); void ca_pow_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx); void ca_pow_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx); void ca_pow(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx); void ca_pow_si_arithmetic(ca_t res, const ca_t x, slong n, ca_ctx_t ctx); void ca_sqrt_inert(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_sqrt_nofactor(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_sqrt_factor(ca_t res, const ca_t x, ulong flags, ca_ctx_t ctx); void ca_sqrt(ca_t res, const ca_t x, ca_ctx_t ctx); CA_INLINE void ca_sqrt_ui(ca_t res, ulong n, ca_ctx_t ctx) { ca_set_ui(res, n, ctx); ca_sqrt(res, res, ctx); } /* Complex parts */ void ca_conj_shallow(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_conj_deep(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_conj(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_abs(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_sgn(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_csgn(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_arg(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_re(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_im(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_floor(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_ceil(ca_t res, const ca_t x, ca_ctx_t ctx); /* Elementary functions */ void ca_exp(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_log(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_sin_cos_exponential(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx); void ca_sin_cos_direct_exp_hack(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx); void ca_sin_cos_direct(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx); void ca_sin_cos_tangent(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx); void ca_sin_cos(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx); void ca_sin(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_cos(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_tan_sine_cosine(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_tan_exponential(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_tan_direct(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_tan(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_cot(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_atan_logarithm(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_atan_direct(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_atan(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_asin_logarithm(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_asin_direct(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_asin(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_acos_logarithm(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_acos_direct(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_acos(ca_t res, const ca_t x, ca_ctx_t ctx); /* Special functions */ void ca_erf(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_erfc(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_erfi(ca_t res, const ca_t x, ca_ctx_t ctx); void ca_gamma(ca_t res, const ca_t x, ca_ctx_t ctx); /* Numerical evaluation */ void ca_get_acb_raw(acb_t res, const ca_t x, slong prec, ca_ctx_t ctx); void ca_get_acb(acb_t res, const ca_t x, slong prec, ca_ctx_t ctx); void ca_get_acb_accurate_parts(acb_t res, const ca_t x, slong prec, ca_ctx_t ctx); char * ca_get_decimal_str(const ca_t x, slong digits, ulong flags, ca_ctx_t ctx); /* Factorisation */ #define CA_FACTOR_ZZ_NONE 0 #define CA_FACTOR_ZZ_SMOOTH 2 #define CA_FACTOR_ZZ_FULL 4 #define CA_FACTOR_POLY_NONE 0 #define CA_FACTOR_POLY_CONTENT 64 #define CA_FACTOR_POLY_SQF 128 #define CA_FACTOR_POLY_FULL 256 typedef struct { ca_ptr base; ca_ptr exp; slong length; slong alloc; } ca_factor_struct; typedef ca_factor_struct ca_factor_t[1]; void ca_factor_init(ca_factor_t fac, ca_ctx_t ctx); void ca_factor_clear(ca_factor_t fac, ca_ctx_t ctx); void ca_factor_one(ca_factor_t fac, ca_ctx_t ctx); void ca_factor_print(const ca_factor_t fac, ca_ctx_t ctx); void ca_factor_insert(ca_factor_t fac, const ca_t base, const ca_t exp, ca_ctx_t ctx); void ca_factor_get_ca(ca_t res, const ca_factor_t fac, ca_ctx_t ctx); void ca_factor(ca_factor_t res, const ca_t x, ulong flags, ca_ctx_t ctx); /* Test helpers */ #define CA_TEST_PROPERTY(f, s, x, ctx, expected) \ do { \ truth_t t; \ t = f(x, ctx); \ if (t != expected) \ { \ flint_printf("FAIL\n"); \ flint_printf("%s\n\n", s); \ flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); \ flint_printf("got = "); truth_print(t); flint_printf("\n\n"); \ flint_printf("expected = "); truth_print(expected); flint_printf("\n\n"); \ flint_abort(); \ } \ } while (0) \ #ifdef __cplusplus } #endif #endif calcium-0.4.1/ca/000077500000000000000000000000001407704557200135275ustar00rootroot00000000000000calcium-0.4.1/ca/abs.c000066400000000000000000000023201407704557200144350ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_abs(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (CA_IS_INF(x)) ca_pos_inf(res, ctx); else ca_set(res, x, ctx); } else if (CA_IS_QQ(x, ctx)) { if (fmpz_sgn(fmpq_numref(CA_FMPQ(x))) >= 0) ca_set(res, x, ctx); else ca_neg(res, x, ctx); } else { qqbar_t t; qqbar_init(t); if (ca_get_qqbar(t, x, ctx)) { qqbar_abs(t, t); if (qqbar_within_limits(t, ctx->options[CA_OPT_QQBAR_DEG_LIMIT], 0)) ca_set_qqbar(res, t, ctx); else _ca_function_fx(res, CA_Abs, x, ctx); } else { _ca_function_fx(res, CA_Abs, x, ctx); } qqbar_clear(t); } } calcium-0.4.1/ca/add.c000066400000000000000000000323701407704557200144300ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void _ca_mpoly_q_reduce_ideal(fmpz_mpoly_q_t res, ca_field_srcptr field, ca_ctx_t ctx) { slong i, n; n = CA_FIELD_IDEAL_LENGTH(field); /* todo: optimizations */ if (n > 0) { fmpz_mpoly_struct ** I; fmpz_mpoly_struct ** Q; fmpq_t scale; I = flint_malloc(sizeof(fmpz_mpoly_struct *) * n); for (i = 0; i < n; i++) I[i] = CA_FIELD_IDEAL_ELEM(field, i); Q = flint_malloc(sizeof(fmpz_mpoly_struct *) * n); for (i = 0; i < n; i++) { Q[i] = flint_malloc(sizeof(fmpz_mpoly_struct)); fmpz_mpoly_init(Q[i], CA_FIELD_MCTX(field, ctx)); } fmpq_init(scale); if (0) { fmpz_mpoly_quasidivrem_ideal(fmpq_denref(scale), Q, fmpz_mpoly_q_numref(res), fmpz_mpoly_q_numref(res), I, n, CA_FIELD_MCTX(field, ctx)); fmpz_mpoly_quasidivrem_ideal(fmpq_numref(scale), Q, fmpz_mpoly_q_denref(res), fmpz_mpoly_q_denref(res), I, n, CA_FIELD_MCTX(field, ctx)); fmpq_canonicalise(scale); fmpz_mpoly_q_canonicalise(res, CA_FIELD_MCTX(field, ctx)); fmpz_mpoly_q_mul_fmpq(res, res, scale, CA_FIELD_MCTX(field, ctx)); } else { fmpz_mpoly_t T; int changed = 0; fmpz_mpoly_init(T, CA_FIELD_MCTX(field, ctx)); fmpz_mpoly_quasidivrem_ideal(fmpq_denref(scale), Q, T, fmpz_mpoly_q_numref(res), I, n, CA_FIELD_MCTX(field, ctx)); changed = !fmpz_mpoly_equal(T, fmpz_mpoly_q_numref(res), CA_FIELD_MCTX(field, ctx)); fmpz_mpoly_swap(T, fmpz_mpoly_q_numref(res), CA_FIELD_MCTX(field, ctx)); /* todo: special case const den */ fmpz_mpoly_quasidivrem_ideal(fmpq_numref(scale), Q, T, fmpz_mpoly_q_denref(res), I, n, CA_FIELD_MCTX(field, ctx)); changed = changed || !fmpz_mpoly_equal(T, fmpz_mpoly_q_denref(res), CA_FIELD_MCTX(field, ctx)); fmpz_mpoly_swap(T, fmpz_mpoly_q_denref(res), CA_FIELD_MCTX(field, ctx)); if (changed) { fmpz_mpoly_q_canonicalise(res, CA_FIELD_MCTX(field, ctx)); } if (!fmpq_is_one(scale)) { fmpq_canonicalise(scale); fmpz_mpoly_q_mul_fmpq(res, res, scale, CA_FIELD_MCTX(field, ctx)); } #if 0 if (!fmpz_mpoly_q_is_canonical(res, CA_FIELD_MCTX(field, ctx))) { flint_printf("not canonical!\n"); flint_abort(); } #endif fmpz_mpoly_clear(T, CA_FIELD_MCTX(field, ctx)); } for (i = 0; i < n; i++) { fmpz_mpoly_clear(Q[i], CA_FIELD_MCTX(field, ctx)); flint_free(Q[i]); } flint_free(Q); flint_free(I); fmpq_clear(scale); } } /* This is currently very simplistic: just try to move monomial factors in the denominator to the numerator. */ void _ca_mpoly_q_simplify_fraction_ideal(fmpz_mpoly_q_t res, ca_field_srcptr field, ca_ctx_t ctx) { slong i, ideal_len; int changed; fmpz_mpoly_ctx_struct * mctx; fmpz_mpoly_t t, u, g, q; fmpz_mpoly_q_t f; ideal_len = CA_FIELD_IDEAL_LENGTH(field); if (ideal_len == 0) return; mctx = CA_FIELD_MCTX(field, ctx); if (fmpz_mpoly_is_fmpz(fmpz_mpoly_q_denref(res), mctx)) return; fmpz_mpoly_init(t, mctx); while (1) { changed = 0; /* todo: only need monomial content? there should be a fmpz_mpoly_monomial_content */ fmpz_mpoly_term_content(t, fmpz_mpoly_q_denref(res), mctx); if (fmpz_mpoly_is_fmpz(t, mctx)) break; fmpz_one(t->coeffs); fmpz_mpoly_init(u, mctx); fmpz_mpoly_init(g, mctx); fmpz_mpoly_init(q, mctx); fmpz_mpoly_q_init(f, mctx); for (i = 0; i < ideal_len; i++) { /* todo: error checks */ fmpz_mpoly_get_term_monomial(u, CA_FIELD_IDEAL_ELEM(field, i), 0, mctx); fmpz_mpoly_gcd(g, t, u, mctx); if (fmpz_mpoly_is_fmpz(g, mctx)) continue; _fmpz_mpoly_q_mpoly_divexact(q, u, g, mctx); fmpz_mpoly_mul(fmpz_mpoly_q_numref(f), fmpz_mpoly_q_numref(res), q, mctx); fmpz_mpoly_mul(fmpz_mpoly_q_denref(f), fmpz_mpoly_q_denref(res), q, mctx); _ca_mpoly_q_reduce_ideal(f, field, ctx); if (fmpz_mpoly_cmp(fmpz_mpoly_q_denref(f), fmpz_mpoly_q_denref(res), mctx) < 0) { changed = 1; fmpz_mpoly_q_swap(res, f, mctx); break; } } fmpz_mpoly_clear(u, mctx); fmpz_mpoly_clear(g, mctx); fmpz_mpoly_clear(q, mctx); fmpz_mpoly_q_clear(f, mctx); if (!changed) break; } fmpz_mpoly_clear(t, mctx); } void ca_add_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx) { ca_field_srcptr field; if (fmpq_is_zero(y) || CA_IS_SPECIAL(x)) { ca_set(res, x, ctx); return; } if (CA_IS_QQ(x, ctx)) { _ca_make_fmpq(res, ctx); fmpq_add(CA_FMPQ(res), CA_FMPQ(x), y); } else { field = CA_FIELD(x, ctx); _ca_make_field_element(res, field, ctx); if (CA_FIELD_IS_NF(field)) nf_elem_add_fmpq(CA_NF_ELEM(res), CA_NF_ELEM(x), y, CA_FIELD_NF(field)); else fmpz_mpoly_q_add_fmpq(CA_MPOLY_Q(res), CA_MPOLY_Q(x), y, CA_FIELD_MCTX(field, ctx)); } } void ca_add_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx) { fmpq_t t; *fmpq_numref(t) = *y; *fmpq_denref(t) = 1; ca_add_fmpq(res, x, t, ctx); } void ca_add_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx) { fmpz_t t; fmpz_init_set_ui(t, y); ca_add_fmpz(res, x, t, ctx); fmpz_clear(t); } void ca_add_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx) { fmpz_t t; fmpz_init_set_si(t, y); ca_add_fmpz(res, x, t, ctx); fmpz_clear(t); } void ca_add(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) { ca_field_srcptr xfield, yfield, zfield; xfield = CA_FIELD(x, ctx); yfield = CA_FIELD(y, ctx); if (CA_IS_QQ(x, ctx) && (xfield == yfield)) { _ca_make_fmpq(res, ctx); fmpq_add(CA_FMPQ(res), CA_FMPQ(x), CA_FMPQ(y)); return; } if (CA_IS_QQ(y, ctx)) { if (res == y) { fmpq_t t; fmpq_init(t); fmpq_set(t, CA_FMPQ(y)); ca_add_fmpq(res, x, t, ctx); fmpq_clear(t); } else { ca_add_fmpq(res, x, CA_FMPQ(y), ctx); } return; } if (CA_IS_QQ(x, ctx)) { if (res == x) { fmpq_t t; fmpq_init(t); fmpq_set(t, CA_FMPQ(x)); ca_add_fmpq(res, y, t, ctx); fmpq_clear(t); } else { ca_add_fmpq(res, y, CA_FMPQ(x), ctx); } return; } if (CA_IS_SPECIAL(x) || CA_IS_SPECIAL(y)) { if (CA_IS_UNDEFINED(x) || CA_IS_UNDEFINED(y)) { ca_undefined(res, ctx); return; } if (CA_IS_UNKNOWN(x) || CA_IS_UNKNOWN(y)) { ca_unknown(res, ctx); return; } if (!CA_IS_SPECIAL(y)) { ca_set(res, x, ctx); return; } if (!CA_IS_SPECIAL(x)) { ca_set(res, y, ctx); return; } if (CA_IS_INF(x) && CA_IS_INF(y)) { if (CA_IS_SIGNED_INF(x) && CA_IS_SIGNED_INF(y)) { truth_t eq = ca_check_equal(x, y, ctx); if (eq == T_TRUE) /* sum of infs with same sign */ ca_set(res, x, ctx); else if (eq == T_FALSE) /* sum of infs with different sign */ ca_undefined(res, ctx); else ca_unknown(res, ctx); return; } else { ca_undefined(res, ctx); } return; } ca_unknown(res, ctx); return; } /* In-field operation. */ if (xfield == yfield) { zfield = xfield; _ca_make_field_element(res, zfield, ctx); if (CA_FIELD_IS_NF(zfield)) { nf_elem_add(CA_NF_ELEM(res), CA_NF_ELEM(x), CA_NF_ELEM(y), CA_FIELD_NF(zfield)); } else { fmpz_mpoly_q_add(CA_MPOLY_Q(res), CA_MPOLY_Q(x), CA_MPOLY_Q(y), CA_FIELD_MCTX(zfield, ctx)); _ca_mpoly_q_reduce_ideal(CA_MPOLY_Q(res), zfield, ctx); _ca_mpoly_q_simplify_fraction_ideal(CA_MPOLY_Q(res), zfield, ctx); } ca_condense_field(res, ctx); return; } /* Coerce to a common field. */ { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); ca_merge_fields(t, u, x, y, ctx); ca_add(res, t, u, ctx); ca_condense_field(res, ctx); ca_clear(t, ctx); ca_clear(u, ctx); } } void ca_sub_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx) { ca_field_srcptr field; if (fmpq_is_zero(y) || CA_IS_SPECIAL(x)) { ca_set(res, x, ctx); return; } if (CA_IS_QQ(x, ctx)) { _ca_make_fmpq(res, ctx); fmpq_sub(CA_FMPQ(res), CA_FMPQ(x), y); } else { field = CA_FIELD(x, ctx); _ca_make_field_element(res, field, ctx); if (CA_FIELD_IS_NF(field)) nf_elem_sub_fmpq(CA_NF_ELEM(res), CA_NF_ELEM(x), y, CA_FIELD_NF(field)); else fmpz_mpoly_q_sub_fmpq(CA_MPOLY_Q(res), CA_MPOLY_Q(x), y, CA_FIELD_MCTX(field, ctx)); } } void ca_sub(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) { ca_field_srcptr xfield, yfield, zfield; xfield = CA_FIELD(x, ctx); yfield = CA_FIELD(y, ctx); if (CA_IS_QQ(x, ctx) && (xfield == yfield)) { _ca_make_fmpq(res, ctx); fmpq_sub(CA_FMPQ(res), CA_FMPQ(x), CA_FMPQ(y)); return; } if (CA_IS_QQ(y, ctx)) { if (res == y) { fmpq_t t; fmpq_init(t); fmpq_set(t, CA_FMPQ(y)); ca_sub_fmpq(res, x, t, ctx); fmpq_clear(t); } else { ca_sub_fmpq(res, x, CA_FMPQ(y), ctx); } return; } if (CA_IS_QQ(x, ctx)) { if (res == x) { fmpq_t t; fmpq_init(t); fmpq_set(t, CA_FMPQ(x)); ca_sub_fmpq(res, y, t, ctx); ca_neg(res, res, ctx); fmpq_clear(t); } else { ca_sub_fmpq(res, y, CA_FMPQ(x), ctx); ca_neg(res, res, ctx); } return; } if (CA_IS_SPECIAL(x) || CA_IS_SPECIAL(y)) { ca_t t; ca_init(t, ctx); ca_neg(t, y, ctx); ca_add(res, x, t, ctx); ca_clear(t, ctx); return; } /* In-field operation. */ if (xfield == yfield) { zfield = xfield; _ca_make_field_element(res, zfield, ctx); if (CA_FIELD_IS_NF(zfield)) { nf_elem_sub(CA_NF_ELEM(res), CA_NF_ELEM(x), CA_NF_ELEM(y), CA_FIELD_NF(zfield)); } else { fmpz_mpoly_q_sub(CA_MPOLY_Q(res), CA_MPOLY_Q(x), CA_MPOLY_Q(y), CA_FIELD_MCTX(zfield, ctx)); _ca_mpoly_q_reduce_ideal(CA_MPOLY_Q(res), zfield, ctx); _ca_mpoly_q_simplify_fraction_ideal(CA_MPOLY_Q(res), zfield, ctx); } ca_condense_field(res, ctx); return; } /* Coerce to a common field. */ { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); ca_merge_fields(t, u, x, y, ctx); ca_sub(res, t, u, ctx); ca_condense_field(res, ctx); ca_clear(t, ctx); ca_clear(u, ctx); } } void ca_sub_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx) { fmpq_t t; *fmpq_numref(t) = *y; *fmpq_denref(t) = 1; ca_sub_fmpq(res, x, t, ctx); } void ca_sub_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx) { fmpz_t t; fmpz_init_set_ui(t, y); ca_sub_fmpz(res, x, t, ctx); fmpz_clear(t); } void ca_sub_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx) { fmpz_t t; fmpz_init_set_si(t, y); ca_sub_fmpz(res, x, t, ctx); fmpz_clear(t); } void ca_fmpq_sub(ca_t res, const fmpq_t x, const ca_t y, ca_ctx_t ctx) { ca_sub_fmpq(res, y, x, ctx); ca_neg(res, res, ctx); } void ca_fmpz_sub(ca_t res, const fmpz_t x, const ca_t y, ca_ctx_t ctx) { fmpq_t t; *fmpq_numref(t) = *x; *fmpq_denref(t) = 1; ca_fmpq_sub(res, t, y, ctx); } void ca_ui_sub(ca_t res, ulong x, const ca_t y, ca_ctx_t ctx) { fmpz_t t; fmpz_init_set_ui(t, x); ca_fmpz_sub(res, t, y, ctx); fmpz_clear(t); } void ca_si_sub(ca_t res, slong x, const ca_t y, ca_ctx_t ctx) { fmpz_t t; fmpz_init_set_si(t, x); ca_fmpz_sub(res, t, y, ctx); fmpz_clear(t); } calcium-0.4.1/ca/arg.c000066400000000000000000000027501407704557200144500ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_arg(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (CA_IS_SIGNED_INF(x)) { ca_sgn(res, x, ctx); ca_arg(res, res, ctx); } else if (CA_IS_UNKNOWN(x)) { ca_unknown(res, ctx); } else { ca_undefined(res, ctx); } } else if (CA_IS_QQ(x, ctx)) { if (fmpz_sgn(CA_FMPQ_NUMREF(x)) >= 0) { ca_zero(res, ctx); } else { ca_pi(res, ctx); ca_neg(res, res, ctx); } } else { ca_t s; qqbar_t t; slong p; ulong q; ca_init(s, ctx); qqbar_init(t); ca_sgn(s, x, ctx); if (ca_get_qqbar(t, s, ctx) && qqbar_log_pi_i(&p, &q, t)) { ca_pi(res, ctx); ca_mul_si(res, res, p, ctx); ca_div_ui(res, res, q, ctx); } else { _ca_function_fx(res, CA_Arg, x, ctx); } ca_clear(s, ctx); qqbar_clear(t); } } calcium-0.4.1/ca/asin.c000066400000000000000000000066161407704557200146360ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_asin_special(ca_t res, const ca_t x, ca_ctx_t ctx) { if (ca_check_is_signed_inf(x, ctx) == T_TRUE) { ca_t s; ca_init(s, ctx); /* -i*csgn(i*z)*inf */ ca_i(s, ctx); ca_mul(res, x, s, ctx); ca_csgn(res, res, ctx); ca_mul(res, res, s, ctx); ca_neg(res, res, ctx); ca_pos_inf(s, ctx); ca_mul(res, res, s, ctx); ca_clear(s, ctx); return; } if (ca_check_is_uinf(x, ctx) == T_TRUE || ca_check_is_undefined(x, ctx) == T_TRUE) { ca_set(res, x, ctx); return; } ca_unknown(res, ctx); return; } static int _ca_asin_rational(ca_t res, const ca_t x, ca_ctx_t ctx) { qqbar_t v; slong p; ulong q; int success; qqbar_init(v); /* todo: rule out non-sines more quickly */ if (ca_get_qqbar(v, x, ctx) && qqbar_asin_pi(&p, &q, v)) { ca_pi(res, ctx); ca_mul_si(res, res, p, ctx); ca_div_ui(res, res, q, ctx); success = 1; } else { success = 0; } qqbar_clear(v); return success; } void ca_asin_logarithm(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t t, u; if (CA_IS_SPECIAL(x)) { ca_asin_special(res, x, ctx); return; } if (_ca_asin_rational(res, x, ctx)) return; /* asin(x) = -i log(ix + sqrt(1-x^2)) */ ca_init(t, ctx); ca_init(u, ctx); ca_sqr(t, x, ctx); ca_ui_sub(t, 1, t, ctx); ca_sqrt(t, t, ctx); ca_i(u, ctx); ca_mul(u, u, x, ctx); ca_add(t, t, u, ctx); ca_log(t, t, ctx); ca_i(u, ctx); ca_mul(res, t, u, ctx); ca_neg(res, res, ctx); ca_clear(t, ctx); ca_clear(u, ctx); } void ca_asin_direct(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { ca_asin_special(res, x, ctx); return; } if (_ca_asin_rational(res, x, ctx)) return; /* todo: csgn normalization, reflection...? */ _ca_function_fx(res, CA_Asin, x, ctx); } void ca_asin(ca_t res, const ca_t x, ca_ctx_t ctx) { if (ctx->options[CA_OPT_TRIG_FORM] == CA_TRIG_EXPONENTIAL) { ca_asin_logarithm(res, x, ctx); } /* todo: else if (ctx->options[CA_OPT_TRIG_FORM] == CA_TRIG_TANGENT) { ca_asin_arctangent(res, x, ctx); } */ else { ca_asin_direct(res, x, ctx); } } void ca_acos_logarithm(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t t; ca_init(t, ctx); ca_pi(t, ctx); ca_div_ui(t, t, 2, ctx); ca_asin_logarithm(res, x, ctx); ca_sub(res, t, res, ctx); ca_clear(t, ctx); } void ca_acos_direct(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t t; ca_init(t, ctx); ca_pi(t, ctx); ca_div_ui(t, t, 2, ctx); ca_asin_direct(res, x, ctx); ca_sub(res, t, res, ctx); ca_clear(t, ctx); } void ca_acos(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t t; ca_init(t, ctx); ca_pi(t, ctx); ca_div_ui(t, t, 2, ctx); ca_asin(res, x, ctx); ca_sub(res, t, res, ctx); ca_clear(t, ctx); } calcium-0.4.1/ca/atan.c000066400000000000000000000102071407704557200146160ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_atan_special(ca_t res, const ca_t x, ca_ctx_t ctx) { if (ca_check_is_signed_inf(x, ctx) == T_TRUE) { ca_t s; ca_init(s, ctx); ca_csgn(s, x, ctx); if (ca_check_is_one(s, ctx) == T_TRUE) { ca_pi(res, ctx); ca_div_ui(res, res, 2, ctx); } else if (ca_check_is_neg_one(s, ctx) == T_TRUE) { ca_pi(res, ctx); ca_div_ui(res, res, 2, ctx); ca_neg(res, res, ctx); } else { ca_unknown(res, ctx); } ca_clear(s, ctx); return; } if (ca_check_is_uinf(x, ctx) == T_TRUE || ca_check_is_undefined(x, ctx) == T_TRUE) { ca_undefined(res, ctx); return; } ca_unknown(res, ctx); return; } static int _ca_atan_rational(ca_t res, const ca_t x, ca_ctx_t ctx) { qqbar_t v; slong p; ulong q; int success; qqbar_init(v); /* todo: rule out non-tangents more quickly */ if (ca_get_qqbar(v, x, ctx) && qqbar_atan_pi(&p, &q, v)) { ca_pi(res, ctx); ca_mul_si(res, res, p, ctx); ca_div_ui(res, res, q, ctx); success = 1; } else { success = 0; } qqbar_clear(v); return success; } void ca_atan_logarithm(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t t, u, v; acb_t z; arb_t one, minus_one; if (CA_IS_SPECIAL(x)) { ca_atan_special(res, x, ctx); return; } if (_ca_atan_rational(res, x, ctx)) return; acb_init(z); arb_init(one); arb_init(minus_one); ca_init(t, ctx); ca_init(u, ctx); ca_init(v, ctx); ca_i(t, ctx); ca_mul(u, x, t, ctx); /* v = 1 + i x */ ca_add_ui(v, u, 1, ctx); /* res = 1 - i x */ ca_sub_ui(res, u, 1, ctx); ca_neg(res, res, ctx); ca_get_acb(z, x, ctx->options[CA_OPT_LOW_PREC], ctx); arb_set_si(one, 1); arb_set_si(minus_one, -1); if (arb_lt(acb_imagref(z), one)) { /* atan(x) = i/2 log((1-ix)/(1+ix)) */ ca_div(res, res, v, ctx); ca_log(res, res, ctx); ca_mul(res, res, t, ctx); ca_div_ui(res, res, 2, ctx); } else if (arb_gt(acb_imagref(z), minus_one)) { /* atan(x) = -i/2 log((1+ix)/(1-ix)) */ ca_div(res, v, res, ctx); ca_log(res, res, ctx); ca_mul(res, res, t, ctx); ca_div_ui(res, res, 2, ctx); ca_neg(res, res, ctx); } else { /* atan(x) = i/2 (log(1-ix) - log(1+ix)) */ ca_log(res, res, ctx); ca_log(v, v, ctx); ca_sub(res, res, v, ctx); ca_mul(res, res, t, ctx); ca_div_ui(res, res, 2, ctx); } ca_clear(t, ctx); ca_clear(u, ctx); ca_clear(v, ctx); acb_clear(z); arb_clear(one); arb_clear(minus_one); } void ca_atan_direct(ca_t res, const ca_t x, ca_ctx_t ctx) { truth_t pole; if (CA_IS_SPECIAL(x)) { ca_atan_special(res, x, ctx); return; } if (_ca_atan_rational(res, x, ctx)) return; pole = ca_check_is_i(x, ctx); if (pole == T_TRUE) { ca_pos_i_inf(res, ctx); return; } if (pole == T_UNKNOWN) { ca_unknown(res, ctx); return; } pole = ca_check_is_neg_i(x, ctx); if (pole == T_TRUE) { ca_neg_i_inf(res, ctx); return; } if (pole == T_UNKNOWN) { ca_unknown(res, ctx); return; } /* todo: csgn normalization, reflection...? */ _ca_function_fx(res, CA_Atan, x, ctx); } void ca_atan(ca_t res, const ca_t x, ca_ctx_t ctx) { if (ctx->options[CA_OPT_TRIG_FORM] == CA_TRIG_EXPONENTIAL) { ca_atan_logarithm(res, x, ctx); } else { ca_atan_direct(res, x, ctx); } } calcium-0.4.1/ca/can_evaluate_qqbar.c000066400000000000000000000037311407704557200175140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int ca_ext_can_evaluate_qqbar(const ca_ext_t x, ca_ctx_t ctx) { if (CA_EXT_IS_QQBAR(x)) return 1; if (CA_EXT_HEAD(x) == CA_Sqrt || CA_EXT_HEAD(x) == CA_Sign || CA_EXT_HEAD(x) == CA_Abs || CA_EXT_HEAD(x) == CA_Re || CA_EXT_HEAD(x) == CA_Im || CA_EXT_HEAD(x) == CA_Conjugate || CA_EXT_HEAD(x) == CA_Floor || CA_EXT_HEAD(x) == CA_Ceil) return ca_can_evaluate_qqbar(CA_EXT_FUNC_ARGS(x), ctx); if (CA_EXT_HEAD(x) == CA_Pow) return ca_can_evaluate_qqbar(CA_EXT_FUNC_ARGS(x), ctx) && CA_IS_QQ(CA_EXT_FUNC_ARGS(x) + 1, ctx); return 0; } int ca_can_evaluate_qqbar(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { return 0; } else if (CA_IS_QQ(x, ctx)) { return 1; } else if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { return 1; } else { slong nvars, i; int res; int * used; nvars = CA_FIELD_LENGTH(CA_FIELD(x, ctx)); used = flint_calloc(nvars, sizeof(int)); fmpz_mpoly_q_used_vars(used, CA_MPOLY_Q(x), CA_FIELD_MCTX(CA_FIELD(x, ctx), ctx)); res = 1; /* todo: exclude extension numbers that are not actually used */ for (i = 0; i < nvars; i++) { if (used[i]) { if (!ca_ext_can_evaluate_qqbar(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i), ctx)) { res = 0; break; } } } flint_free(used); return res; } } calcium-0.4.1/ca/ceil.c000066400000000000000000000040211407704557200146040ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_ceil(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (CA_IS_UNKNOWN(x)) ca_unknown(res, ctx); else ca_undefined(res, ctx); return; } if (CA_IS_QQ(x, ctx)) { fmpz_t t; fmpz_init(t); fmpz_cdiv_q(t, CA_FMPQ_NUMREF(x), CA_FMPQ_DENREF(x)); ca_set_fmpz(res, t, ctx); fmpz_clear(t); return; } { slong prec, prec_limit; acb_t v; mag_t m; fmpz_t n; int success = 0; acb_init(v); mag_init(m); fmpz_init(n); prec_limit = ctx->options[CA_OPT_PREC_LIMIT]; prec_limit = FLINT_MAX(prec_limit, 64); for (prec = 64; (prec <= prec_limit) && !success; prec *= 2) { ca_get_acb_raw(v, x, prec, ctx); arb_get_mag(m, acb_realref(v)); if (arb_is_finite(acb_imagref(v)) && mag_cmp_2exp_si(m, prec_limit) <= 0) { arb_ceil(acb_realref(v), acb_realref(v), prec); if (arb_get_unique_fmpz(n, acb_realref(v))) { ca_set_fmpz(res, n, ctx); success = 1; break; } } arb_get_mag_lower(m, acb_realref(v)); if (mag_cmp_2exp_si(m, prec_limit) > 0) break; } acb_clear(v); mag_clear(m); fmpz_clear(n); if (success) return; } _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Ceil, x), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } calcium-0.4.1/ca/check_equal.c000066400000000000000000000066431407704557200161500ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_equal(const ca_t x, const ca_t y, ca_ctx_t ctx) { acb_t u, v; ca_t t; truth_t res; truth_t x_alg, y_alg; slong prec; if (CA_IS_QQ(x, ctx) && CA_IS_QQ(y, ctx)) { return fmpq_equal(CA_FMPQ(x), CA_FMPQ(y)) ? T_TRUE : T_FALSE; } if (CA_IS_SPECIAL(x) || CA_IS_SPECIAL(y)) { if (CA_IS_UNKNOWN(x) || CA_IS_UNKNOWN(y)) return T_UNKNOWN; if (CA_IS_SIGNED_INF(x) && CA_IS_SIGNED_INF(y)) { ca_t xsign, ysign; *xsign = *x; *ysign = *y; xsign->field &= ~CA_SPECIAL; ysign->field &= ~CA_SPECIAL; return ca_check_equal(xsign, ysign, ctx); } if (x->field == y->field) return T_TRUE; else return T_FALSE; } if (ca_equal_repr(x, y, ctx)) return T_TRUE; /* same algebraic number field ==> sufficient to compare representation */ if (x->field == y->field && CA_FIELD_IS_NF(CA_FIELD(x, ctx))) return T_FALSE; /* Rational number field elements *should* have been demoted to QQ automatically, but let's do a comparison as a precaution. */ if (CA_FIELD_IS_NF(CA_FIELD(x, ctx)) && CA_IS_QQ(y, ctx)) return nf_elem_equal_fmpq(CA_NF_ELEM(x), CA_FMPQ(y), CA_FIELD_NF(CA_FIELD(x, ctx))) ? T_TRUE : T_FALSE; if (CA_FIELD_IS_NF(CA_FIELD(y, ctx)) && CA_IS_QQ(x, ctx)) return nf_elem_equal_fmpq(CA_NF_ELEM(y), CA_FMPQ(x), CA_FIELD_NF(CA_FIELD(y, ctx))) ? T_TRUE : T_FALSE; res = T_UNKNOWN; acb_init(u); acb_init(v); /* for (prec = 64; (prec <= ctx->options[CA_OPT_PREC_LIMIT]) && (res == T_UNKNOWN); prec *= 2) */ prec = 64; { ca_get_acb_raw(u, x, prec, ctx); ca_get_acb_raw(v, y, prec, ctx); if (!acb_overlaps(u, v)) { res = T_FALSE; } } acb_clear(u); acb_clear(v); x_alg = ca_check_is_algebraic(x, ctx); y_alg = ca_check_is_algebraic(y, ctx); if ((x_alg == T_TRUE && y_alg == T_FALSE) || (x_alg == T_FALSE && y_alg == T_TRUE)) return T_FALSE; /* todo: try qqbar computation */ /* we may want to do this selectively; in some cases cancellation in computing x-y will be helpful; in other cases, subtracting the terms will make life more difficult */ if (0 && x_alg == T_TRUE && y_alg == T_TRUE) { /* ... qqbar_t a, b; qqbar_init(a); qqbar_init(b); if (ca_get_qqbar(a, x, ctx)) { if (ca_get_qqbar(b, y, ctx)) { int eq = qqbar_equal(a, b); qqbar_clear(a); qqbar_clear(b); return eq ? T_TRUE : T_FALSE; } } qqbar_clear(a); qqbar_clear(b); */ } if (res == T_UNKNOWN) { /* check_is_zero may have additional heuristics */ ca_init(t, ctx); ca_sub(t, x, y, ctx); res = ca_check_is_zero(t, ctx); ca_clear(t, ctx); } return res; } calcium-0.4.1/ca/check_ge.c000066400000000000000000000166471407704557200154410ustar00rootroot00000000000000/* Copyright (C) 2020, 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #define CMP_UNDEFINED -2 #define CMP_UNKNOWN -3 int _ca_cmp(const ca_t x, const ca_t y, ca_ctx_t ctx) { acb_t v, w; truth_t x_real, y_real; slong prec, prec_limit; int result; if (CA_IS_QQ(x, ctx) && CA_IS_QQ(y, ctx)) { result = fmpq_cmp(CA_FMPQ(x), CA_FMPQ(y)); if (result < 0) result = -1; if (result > 0) result = 1; return result; } if (CA_IS_SPECIAL(x) || CA_IS_SPECIAL(y)) { if (ca_check_is_pos_inf(x, ctx) == T_TRUE) { if (ca_check_is_pos_inf(y, ctx) == T_TRUE) return 0; if (ca_check_is_neg_inf(y, ctx) == T_TRUE) return 1; y_real = ca_check_is_real(y, ctx); if (y_real == T_TRUE) return 1; if (y_real == T_FALSE) return CMP_UNDEFINED; return CMP_UNKNOWN; } if (ca_check_is_neg_inf(x, ctx) == T_TRUE) { if (ca_check_is_neg_inf(y, ctx) == T_TRUE) return 0; if (ca_check_is_pos_inf(y, ctx) == T_TRUE) return -1; y_real = ca_check_is_real(y, ctx); if (y_real == T_TRUE) return -1; if (y_real == T_FALSE) return CMP_UNDEFINED; return CMP_UNKNOWN; } if (ca_check_is_pos_inf(y, ctx) == T_TRUE) { if (ca_check_is_pos_inf(x, ctx) == T_TRUE) return 0; if (ca_check_is_neg_inf(x, ctx) == T_TRUE) return -1; x_real = ca_check_is_real(x, ctx); if (x_real == T_TRUE) return -1; if (x_real == T_FALSE) return CMP_UNDEFINED; return CMP_UNKNOWN; } if (ca_check_is_neg_inf(y, ctx) == T_TRUE) { if (ca_check_is_neg_inf(x, ctx) == T_TRUE) return 0; if (ca_check_is_pos_inf(x, ctx) == T_TRUE) return 1; x_real = ca_check_is_real(x, ctx); if (x_real == T_TRUE) return 1; if (x_real == T_FALSE) return CMP_UNDEFINED; return CMP_UNKNOWN; } /* Not comparable */ if (ca_check_is_undefined(x, ctx) == T_TRUE || ca_check_is_undefined(y, ctx) == T_TRUE || ca_check_is_uinf(x, ctx) == T_TRUE || ca_check_is_uinf(y, ctx) == T_TRUE || (ca_check_is_signed_inf(x, ctx) == T_TRUE && ca_check_is_pos_inf(x, ctx) == T_FALSE && ca_check_is_neg_inf(x, ctx) == T_FALSE) || (ca_check_is_signed_inf(y, ctx) == T_TRUE && ca_check_is_pos_inf(y, ctx) == T_FALSE && ca_check_is_neg_inf(y, ctx) == T_FALSE) || (ca_check_is_number(x, ctx) == T_TRUE && ca_check_is_real(x, ctx) == T_FALSE) || (ca_check_is_number(y, ctx) == T_TRUE && ca_check_is_real(y, ctx) == T_FALSE)) { return CMP_UNDEFINED; } return CMP_UNKNOWN; } result = CMP_UNKNOWN; x_real = y_real = T_UNKNOWN; acb_init(v); acb_init(w); prec_limit = ctx->options[CA_OPT_PREC_LIMIT]; prec_limit = FLINT_MAX(prec_limit, 64); for (prec = 64; (prec <= prec_limit) && (result == CMP_UNKNOWN); prec *= 2) { ca_get_acb_raw(v, x, prec, ctx); ca_get_acb_raw(w, y, prec, ctx); if (arb_is_zero(acb_imagref(v))) x_real = T_TRUE; else if (!arb_contains_zero(acb_imagref(v))) x_real = T_FALSE; if (arb_is_zero(acb_imagref(w))) y_real = T_TRUE; else if (!arb_contains_zero(acb_imagref(w))) y_real = T_FALSE; if (x_real == T_FALSE || y_real == T_FALSE) { /* Not comparable */ result = CMP_UNDEFINED; break; } /* Force a verification that we have comparable numbers. */ if (x_real == T_UNKNOWN && prec == 64) x_real = ca_check_is_real(x, ctx); if (y_real == T_UNKNOWN && prec == 64) y_real = ca_check_is_real(y, ctx); if (x_real == T_FALSE || y_real == T_FALSE) { /* Not comparable */ result = CMP_UNDEFINED; break; } if (x_real == T_TRUE && y_real == T_TRUE) { if (arb_gt(acb_realref(v), acb_realref(w))) { result = 1; break; } else if (arb_lt(acb_realref(v), acb_realref(w))) { result = -1; break; } } /* try qqbar computation */ /* todo: precision to do this should depend on complexity of the polynomials, degree of the elements... */ if (prec == 64) { if (ca_can_evaluate_qqbar(x, ctx) && ca_can_evaluate_qqbar(y, ctx)) { qqbar_t t, u; qqbar_init(t); qqbar_init(u); if (ca_get_qqbar(t, x, ctx)) { if (!qqbar_is_real(t)) { /* Not comparable */ result = CMP_UNDEFINED; } else if (ca_get_qqbar(u, y, ctx)) { if (!qqbar_is_real(u)) { /* Not comparable */ result = CMP_UNDEFINED; } else { result = qqbar_cmp_re(t, u); if (result < 0) result = -1; if (result > 0) result = 1; } } } qqbar_clear(t); qqbar_clear(u); } } } /* Todo: subtract, compute sign? Symbolic cancellations may help. */ if (result == CMP_UNKNOWN && x_real == T_TRUE && y_real == T_TRUE) { if (ca_check_equal(x, y, ctx) == T_TRUE) result = 0; } acb_clear(v); acb_clear(w); return result; } truth_t ca_check_ge(const ca_t x, const ca_t y, ca_ctx_t ctx) { int c = _ca_cmp(x, y, ctx); if (c == CMP_UNKNOWN) return T_UNKNOWN; if (c == CMP_UNDEFINED) return T_FALSE; return (c >= 0) ? T_TRUE : T_FALSE; } truth_t ca_check_gt(const ca_t x, const ca_t y, ca_ctx_t ctx) { int c = _ca_cmp(x, y, ctx); if (c == CMP_UNKNOWN) return T_UNKNOWN; if (c == CMP_UNDEFINED) return T_FALSE; return (c > 0) ? T_TRUE : T_FALSE; } truth_t ca_check_lt(const ca_t x, const ca_t y, ca_ctx_t ctx) { int c = _ca_cmp(x, y, ctx); if (c == CMP_UNKNOWN) return T_UNKNOWN; if (c == CMP_UNDEFINED) return T_FALSE; return (c < 0) ? T_TRUE : T_FALSE; } truth_t ca_check_le(const ca_t x, const ca_t y, ca_ctx_t ctx) { int c = _ca_cmp(x, y, ctx); if (c == CMP_UNKNOWN) return T_UNKNOWN; if (c == CMP_UNDEFINED) return T_FALSE; return (c <= 0) ? T_TRUE : T_FALSE; } calcium-0.4.1/ca/check_gt.c000066400000000000000000000006521407704557200154450ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" /* see check_ge.c */ calcium-0.4.1/ca/check_is_algebraic.c000066400000000000000000000030001407704557200174250ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int ca_ext_can_evaluate_qqbar(const ca_ext_t x, ca_ctx_t ctx); /* todo: move, rename */ static truth_t ca_ext_is_algebraic(const ca_ext_t x, ca_ctx_t ctx) { if (CA_EXT_IS_QQBAR(x)) return T_TRUE; if (ca_ext_can_evaluate_qqbar(x, ctx)) return T_TRUE; return T_UNKNOWN; } truth_t ca_check_is_algebraic(const ca_t x, ca_ctx_t ctx) { ca_field_srcptr field; if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } field = CA_FIELD(x, ctx); if (CA_IS_QQ(x, ctx) || CA_FIELD_IS_NF(field)) { return T_TRUE; } else { slong len, i; len = CA_FIELD_LENGTH(field); /* todo: handle simple transcendental numbers, e.g. Q(i,pi) */ /* need to verify that some generator is used in the poly */ /* for Q(a,b,pi) we don't know, because a, b could cancel out pi */ for (i = 0; i < len; i++) { if (ca_ext_is_algebraic(CA_FIELD_EXT_ELEM(field, i), ctx) != T_TRUE) return T_UNKNOWN; } return T_TRUE; } } calcium-0.4.1/ca/check_is_i.c000066400000000000000000000021521407704557200157530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_i(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } else if (CA_IS_QQ(x, ctx)) { return T_FALSE; } else if (CA_IS_QQ_I(x, ctx)) { const fmpz *n, *d; n = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); d = QNF_ELEM_DENREF(CA_NF_ELEM(x)); if (fmpz_is_one(d) && fmpz_is_zero(n) && fmpz_is_one(n + 1)) return T_TRUE; return T_FALSE; } else { truth_t res; ca_t t; ca_init(t, ctx); ca_i(t, ctx); res = ca_check_equal(x, t, ctx); ca_clear(t, ctx); return res; } } calcium-0.4.1/ca/check_is_imaginary.c000066400000000000000000000047611407704557200175130ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_imaginary(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } else if (CA_IS_QQ(x, ctx)) { if (fmpq_is_zero(CA_FMPQ(x))) return T_TRUE; else return T_FALSE; } else if (CA_IS_QQ_I(x, ctx)) { const fmpz *n; n = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); if (fmpz_is_zero(n)) return T_TRUE; return T_FALSE; } else { acb_t t; truth_t res; slong prec, prec_limit; res = T_UNKNOWN; acb_init(t); prec_limit = ctx->options[CA_OPT_PREC_LIMIT]; prec_limit = FLINT_MAX(prec_limit, 64); for (prec = 64; (prec <= prec_limit) && (res == T_UNKNOWN); prec *= 2) { ca_get_acb_raw(t, x, prec, ctx); if (arb_is_zero(acb_realref(t))) { res = T_TRUE; break; } if (!arb_contains_zero(acb_realref(t))) { res = T_FALSE; break; } /* try conjugation */ /* todo: precision to do this should depend on complexity of the polynomials, degree of the elements... */ if (prec == 64) { ca_t t; ca_init(t, ctx); ca_conj_deep(t, x, ctx); ca_neg(t, t, ctx); res = ca_check_equal(t, x, ctx); ca_clear(t, ctx); if (res != T_UNKNOWN) break; } /* try qqbar computation */ /* todo: precision to do this should depend on complexity of the polynomials, degree of the elements... */ if (prec == 64) { qqbar_t a; qqbar_init(a); if (ca_get_qqbar(a, x, ctx)) res = (qqbar_sgn_re(a) == 0) ? T_TRUE : T_FALSE; qqbar_clear(a); } } acb_clear(t); return res; } } calcium-0.4.1/ca/check_is_infinity.c000066400000000000000000000012351407704557200173550ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_infinity(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; if (CA_IS_INF(x)) return T_TRUE; return T_FALSE; } return T_FALSE; } calcium-0.4.1/ca/check_is_integer.c000066400000000000000000000036041407704557200171630ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" /* todo: fast check in number field */ truth_t ca_check_is_integer(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } else if (CA_IS_QQ(x, ctx)) { if (fmpz_is_one(fmpq_denref(CA_FMPQ(x)))) return T_TRUE; else return T_FALSE; } else if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { return nf_elem_is_integer(CA_NF_ELEM(x), CA_FIELD_NF(CA_FIELD(x, ctx))) ? T_TRUE : T_FALSE; } else { acb_t t; truth_t res; slong prec, prec_limit; res = T_UNKNOWN; acb_init(t); prec_limit = ctx->options[CA_OPT_PREC_LIMIT]; prec_limit = FLINT_MAX(prec_limit, 64); for (prec = 64; (prec <= prec_limit) && (res == T_UNKNOWN); prec *= 2) { ca_get_acb_raw(t, x, prec, ctx); if (!acb_contains_int(t)) { res = T_FALSE; break; } /* try qqbar computation */ /* todo: precision to do this should depend on complexity of the polynomials, degree of the elements... */ if (prec == 64) { qqbar_t a; qqbar_init(a); if (ca_get_qqbar(a, x, ctx)) res = qqbar_is_integer(a) ? T_TRUE : T_FALSE; qqbar_clear(a); } } acb_clear(t); return res; } } calcium-0.4.1/ca/check_is_neg_i.c000066400000000000000000000022161407704557200166050ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_neg_i(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } else if (CA_IS_QQ(x, ctx)) { return T_FALSE; } else if (CA_IS_QQ_I(x, ctx)) { const fmpz *n, *d; n = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); d = QNF_ELEM_DENREF(CA_NF_ELEM(x)); if (fmpz_is_one(d) && fmpz_is_zero(n) && fmpz_equal_si(n + 1, -1)) return T_TRUE; return T_FALSE; } else { truth_t res; ca_t t; ca_init(t, ctx); ca_i(t, ctx); ca_neg(t, t, ctx); res = ca_check_equal(x, t, ctx); ca_clear(t, ctx); return res; } } calcium-0.4.1/ca/check_is_neg_i_inf.c000066400000000000000000000014521407704557200174420ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_neg_i_inf(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; if (CA_IS_SIGNED_INF(x)) { ca_t t; t->field = x->field & ~CA_INF; t->elem = x->elem; return ca_check_is_neg_i(t, ctx); } return T_FALSE; } return T_FALSE; } calcium-0.4.1/ca/check_is_neg_inf.c000066400000000000000000000014521407704557200171320ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_neg_inf(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; if (CA_IS_SIGNED_INF(x)) { ca_t t; t->field = x->field & ~CA_INF; t->elem = x->elem; return ca_check_is_neg_one(t, ctx); } return T_FALSE; } return T_FALSE; } calcium-0.4.1/ca/check_is_neg_one.c000066400000000000000000000024121407704557200171340ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_neg_one(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } else if (CA_IS_QQ(x, ctx)) { if (fmpz_is_one(fmpq_denref(CA_FMPQ(x))) && fmpz_equal_si(fmpq_numref(CA_FMPQ(x)), -1)) return T_TRUE; else return T_FALSE; } else if (CA_IS_QQ_I(x, ctx)) { const fmpz *n, *d; n = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); d = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); if (fmpz_is_one(d) && fmpz_equal_si(n, -1) && fmpz_is_zero(n + 1)) return T_TRUE; return T_FALSE; } else { truth_t res; ca_t t; ca_init(t, ctx); ca_set_si(t, -1, ctx); res = ca_check_equal(x, t, ctx); ca_clear(t, ctx); return res; } } calcium-0.4.1/ca/check_is_negative_real.c000066400000000000000000000054041407704557200203330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_negative_real(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } else if (CA_IS_QQ(x, ctx)) { return (fmpq_sgn(CA_FMPQ(x)) < 0) ? T_TRUE : T_FALSE; } else if (CA_IS_QQ_I(x, ctx)) { const fmpz *n; n = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); if (fmpz_is_zero(n + 1)) return (fmpz_sgn(n) < 0) ? T_TRUE : T_FALSE; return T_FALSE; } else { acb_t t; truth_t res, is_real; slong prec, prec_limit; res = T_UNKNOWN; acb_init(t); prec_limit = ctx->options[CA_OPT_PREC_LIMIT]; prec_limit = FLINT_MAX(prec_limit, 64); is_real = T_UNKNOWN; for (prec = 64; (prec <= prec_limit) && (res == T_UNKNOWN); prec *= 2) { ca_get_acb_raw(t, x, prec, ctx); if (is_real == T_UNKNOWN) { if (arb_is_zero(acb_imagref(t))) is_real = T_TRUE; else if (!arb_contains_zero(acb_imagref(t))) is_real = T_FALSE; } if ((is_real == T_TRUE) && arb_is_negative(acb_realref(t))) { res = T_TRUE; break; } if ((is_real == T_FALSE) || arb_is_nonnegative(acb_realref(t))) { res = T_FALSE; break; } if (prec == 64 && is_real == T_UNKNOWN) { ca_t t; ca_init(t, ctx); ca_conj_deep(t, x, ctx); is_real = ca_check_equal(t, x, ctx); ca_clear(t, ctx); if (is_real == T_FALSE) { res = T_FALSE; break; } } /* try qqbar computation */ /* todo: precision to do this should depend on complexity of the polynomials, degree of the elements... */ if (prec == 64) { qqbar_t a; qqbar_init(a); if (ca_get_qqbar(a, x, ctx)) res = (qqbar_sgn_im(a) == 0 && qqbar_sgn_re(a) < 0) ? T_TRUE : T_FALSE; qqbar_clear(a); } } acb_clear(t); return res; } } calcium-0.4.1/ca/check_is_number.c000066400000000000000000000011451407704557200170140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_number(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } return T_TRUE; } calcium-0.4.1/ca/check_is_one.c000066400000000000000000000022771407704557200163140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_one(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } else if (CA_IS_QQ(x, ctx)) { if (fmpq_is_one(CA_FMPQ(x))) return T_TRUE; else return T_FALSE; } else if (CA_IS_QQ_I(x, ctx)) { const fmpz *n, *d; n = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); d = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); if (fmpz_is_one(d) && fmpz_is_one(n) && fmpz_is_zero(n + 1)) return T_TRUE; return T_FALSE; } else { truth_t res; ca_t t; ca_init(t, ctx); ca_one(t, ctx); res = ca_check_equal(x, t, ctx); ca_clear(t, ctx); return res; } } calcium-0.4.1/ca/check_is_pos_i_inf.c000066400000000000000000000014741407704557200174760ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_field.h" truth_t ca_check_is_pos_i_inf(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; if (CA_IS_SIGNED_INF(x)) { ca_t t; t->field = x->field & ~CA_INF; t->elem = x->elem; return ca_check_is_i(t, ctx); } return T_FALSE; } return T_FALSE; } calcium-0.4.1/ca/check_is_pos_inf.c000066400000000000000000000014461407704557200171650ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_pos_inf(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; if (CA_IS_SIGNED_INF(x)) { ca_t t; t->field = x->field & ~CA_INF; t->elem = x->elem; return ca_check_is_one(t, ctx); } return T_FALSE; } return T_FALSE; } calcium-0.4.1/ca/check_is_rational.c000066400000000000000000000034661407704557200173450ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" /* todo: fast check in number field */ truth_t ca_check_is_rational(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } else if (CA_IS_QQ(x, ctx)) { return T_TRUE; } else if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { return nf_elem_is_rational(CA_NF_ELEM(x), CA_FIELD_NF(CA_FIELD(x, ctx))) ? T_TRUE : T_FALSE; } else { acb_t t; truth_t res; slong prec, prec_limit; res = T_UNKNOWN; acb_init(t); prec_limit = ctx->options[CA_OPT_PREC_LIMIT]; prec_limit = FLINT_MAX(prec_limit, 64); for (prec = 64; (prec <= prec_limit) && (res == T_UNKNOWN); prec *= 2) { ca_get_acb_raw(t, x, prec, ctx); if (!arb_contains_zero(acb_imagref(t))) { res = T_FALSE; break; } /* try qqbar computation */ /* todo: precision to do this should depend on complexity of the polynomials, degree of the elements... */ if (prec == 64) { qqbar_t a; qqbar_init(a); if (ca_get_qqbar(a, x, ctx)) res = qqbar_is_rational(a) ? T_TRUE : T_FALSE; qqbar_clear(a); } } acb_clear(t); return res; } } calcium-0.4.1/ca/check_is_real.c000066400000000000000000000046471407704557200164610ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_real(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } else if (CA_IS_QQ(x, ctx)) { return T_TRUE; } else if (CA_IS_QQ_I(x, ctx)) { const fmpz *n; n = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); if (fmpz_is_zero(n + 1)) return T_TRUE; return T_FALSE; } else /* todo: first inspect extension numbers */ { acb_t t; truth_t res; slong prec, prec_limit; res = T_UNKNOWN; acb_init(t); prec_limit = ctx->options[CA_OPT_PREC_LIMIT]; prec_limit = FLINT_MAX(prec_limit, 64); for (prec = 64; (prec <= prec_limit) && (res == T_UNKNOWN); prec *= 2) { ca_get_acb_raw(t, x, prec, ctx); if (arb_is_zero(acb_imagref(t))) { res = T_TRUE; break; } if (!arb_contains_zero(acb_imagref(t))) { res = T_FALSE; break; } /* try conjugation */ /* todo: precision to do this should depend on complexity of the polynomials, degree of the elements... */ if (prec == 64) { ca_t t; ca_init(t, ctx); ca_conj_deep(t, x, ctx); res = ca_check_equal(t, x, ctx); ca_clear(t, ctx); if (res != T_UNKNOWN) break; } /* try qqbar computation */ /* todo: precision to do this should depend on complexity of the polynomials, degree of the elements... */ if (prec == 64) { qqbar_t a; qqbar_init(a); if (ca_get_qqbar(a, x, ctx)) res = (qqbar_sgn_im(a) == 0) ? T_TRUE : T_FALSE; qqbar_clear(a); } } acb_clear(t); return res; } } calcium-0.4.1/ca/check_is_signed_inf.c000066400000000000000000000012461407704557200176330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_signed_inf(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; if (CA_IS_SIGNED_INF(x)) return T_TRUE; return T_FALSE; } return T_FALSE; } calcium-0.4.1/ca/check_is_uinf.c000066400000000000000000000012421407704557200164630ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_uinf(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; if (CA_IS_UNSIGNED_INF(x)) return T_TRUE; return T_FALSE; } return T_FALSE; } calcium-0.4.1/ca/check_is_undefined.c000066400000000000000000000012441407704557200174650ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t ca_check_is_undefined(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; if (CA_IS_UNDEFINED(x)) return T_TRUE; return T_FALSE; } return T_FALSE; } calcium-0.4.1/ca/check_is_zero.c000066400000000000000000000121471407704557200165070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" truth_t _ca_check_is_zero_qqbar(const ca_t x, ca_ctx_t ctx) { qqbar_t t; truth_t res; qqbar_init(t); if (ca_get_qqbar(t, x, ctx)) res = qqbar_is_zero(t) ? T_TRUE : T_FALSE; else res = T_UNKNOWN; qqbar_clear(t); return res; } void ca_rewrite_complex_normal_form(ca_t res, const ca_t x, int deep, ca_ctx_t ctx); truth_t ca_is_zero_check_fast(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (ca_is_unknown(x, ctx)) return T_UNKNOWN; return T_FALSE; } if (CA_IS_QQ(x, ctx)) { if (fmpq_is_zero(CA_FMPQ(x))) return T_TRUE; else return T_FALSE; } if (CA_IS_QQ_I(x, ctx)) { const fmpz *n; n = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); if (fmpz_is_zero(n) && fmpz_is_zero(n + 1)) return T_TRUE; return T_FALSE; } if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { if (nf_elem_is_zero(CA_NF_ELEM(x), CA_FIELD_NF(CA_FIELD(x, ctx)))) return T_TRUE; else return T_FALSE; } return T_UNKNOWN; } int _ca_generic_has_nontrivial_denominator(const ca_t x, ca_ctx_t ctx) { return !fmpz_mpoly_is_fmpz(fmpz_mpoly_q_denref(CA_MPOLY_Q(x)), CA_FIELD_MCTX(CA_FIELD(x, ctx), ctx)); } truth_t ca_check_is_zero_no_factoring(const ca_t x, ca_ctx_t ctx) { acb_t v; truth_t res; slong prec, prec_limit; res = ca_is_zero_check_fast(x, ctx); if (res != T_UNKNOWN || CA_IS_SPECIAL(x)) return res; /* The denominator is irrelevant. */ /* Todo: we should probably also factor out monomials. */ if (_ca_generic_has_nontrivial_denominator(x, ctx)) { ca_t t; ca_init(t, ctx); ca_set(t, x, ctx); /* Todo: could also remove content */ fmpz_mpoly_one(fmpz_mpoly_q_denref(CA_MPOLY_Q(t)), CA_FIELD_MCTX(CA_FIELD(t, ctx), ctx)); res = ca_check_is_zero_no_factoring(t, ctx); ca_clear(t, ctx); return res; } acb_init(v); prec_limit = ctx->options[CA_OPT_PREC_LIMIT]; prec_limit = FLINT_MAX(prec_limit, 64); for (prec = 64; (prec <= prec_limit) && (res == T_UNKNOWN); prec *= 2) { ca_get_acb_raw(v, x, prec, ctx); if (!acb_contains_zero(v)) { res = T_FALSE; break; } /* try qqbar computation */ /* todo: precision to do this should depend on complexity of the polynomials, degree of the elements... */ if (prec == 64) { res = _ca_check_is_zero_qqbar(x, ctx); } } acb_clear(v); if (res == T_UNKNOWN) { ca_t tmp; ca_init(tmp, ctx); ca_rewrite_complex_normal_form(tmp, x, 1, ctx); res = ca_is_zero_check_fast(tmp, ctx); if (ctx->options[CA_OPT_VERBOSE]) { flint_printf("is_zero: complex_normal form:\n"); ca_print(x, ctx); flint_printf("\n"); ca_print(tmp, ctx); flint_printf("\n"); truth_print(res); flint_printf("\n"); } ca_clear(tmp, ctx); } return res; } truth_t ca_check_is_zero(const ca_t x, ca_ctx_t ctx) { truth_t res; res = ca_check_is_zero_no_factoring(x, ctx); if (res == T_UNKNOWN && !CA_IS_SPECIAL(x)) { ca_factor_t fac; ca_t t; truth_t factor_res; slong i, nontrivial_factors; /* the zero test will surely have succeeded over a number field */ if (!CA_FIELD_IS_GENERIC(CA_FIELD(x, ctx))) flint_abort(); /* extract numerator */ ca_init(t, ctx); ca_set(t, x, ctx); fmpz_mpoly_one(fmpz_mpoly_q_denref(CA_MPOLY_Q(t)), CA_FIELD_MCTX(CA_FIELD(t, ctx), ctx)); ca_factor_init(fac, ctx); ca_factor(fac, t, CA_FACTOR_ZZ_NONE | CA_FACTOR_POLY_FULL, ctx); nontrivial_factors = 0; for (i = 0; i < fac->length; i++) nontrivial_factors += !CA_IS_QQ(fac->base + i, ctx); if (nontrivial_factors >= 2) { for (i = 0; i < fac->length; i++) { factor_res = ca_check_is_zero_no_factoring(fac->base + i, ctx); if (factor_res == T_TRUE) { if (ctx->options[CA_OPT_VERBOSE]) { flint_printf("is_zero: factoring:\n"); ca_print(x, ctx); flint_printf("\n"); ca_print(fac->base + i, ctx); flint_printf("\n"); truth_print(res); flint_printf("\n"); } res = T_TRUE; break; } } } ca_clear(t, ctx); ca_factor_clear(fac, ctx); } return res; } calcium-0.4.1/ca/check_le.c000066400000000000000000000006521407704557200154330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" /* see check_ge.c */ calcium-0.4.1/ca/check_lt.c000066400000000000000000000006521407704557200154520ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" /* see check_ge.c */ calcium-0.4.1/ca/clear.c000066400000000000000000000041171407704557200147640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #define CHECK_DATA 0 void ca_clear_unchecked(ca_t x, ca_ctx_t ctx) { ca_field_srcptr field; field = (ca_field_srcptr) (x->field & ~CA_SPECIAL); if (field != NULL) { if (field == ctx->field_qq) { fmpz_clear(CA_FMPQ_NUMREF(x)); fmpz_clear(CA_FMPQ_DENREF(x)); } else if (CA_FIELD_IS_NF(field)) { nf_elem_clear(CA_NF_ELEM(x), CA_FIELD_NF(field)); } else { fmpz_mpoly_q_clear(CA_MPOLY_Q(x), CA_FIELD_MCTX(field, ctx)); flint_free(x->elem.mpoly_q); } } } void ca_clear(ca_t x, ca_ctx_t ctx) { ca_field_srcptr field; field = (ca_field_srcptr) (x->field & ~CA_SPECIAL); if (field != NULL) { if (field == ctx->field_qq) { fmpz_clear(CA_FMPQ_NUMREF(x)); fmpz_clear(CA_FMPQ_DENREF(x)); } else if (CA_FIELD_IS_NF(field)) { #if CHECK_DATA if (nf_elem_is_rational(CA_NF_ELEM(x), CA_FIELD_NF(field))) { ca_print(x, ctx); printf("\n"); flint_printf("ca_clear: nf_elem is rational!\n"); flint_abort(); } #endif nf_elem_clear(CA_NF_ELEM(x), CA_FIELD_NF(field)); } else { #if CHECK_DATA if (fmpz_mpoly_q_is_fmpq(CA_MPOLY_Q(x), CA_FIELD_MCTX(field, ctx))) { ca_print(x, ctx); printf("\n"); flint_printf("ca_clear: mpoly_q is rational!\n"); flint_abort(); } #endif fmpz_mpoly_q_clear(CA_MPOLY_Q(x), CA_FIELD_MCTX(field, ctx)); flint_free(x->elem.mpoly_q); } } } calcium-0.4.1/ca/condense_field.c000066400000000000000000000156221407704557200166420ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" ca_field_ptr ca_field_cache_lookup_qqbar(ca_field_cache_t cache, const qqbar_t x, ca_ctx_t ctx); static void _fmpz_mpoly_get_fmpq_poly_var_destructive(fmpq_poly_t res, fmpz_mpoly_t F, slong i, const fmpz_mpoly_ctx_t ctx) { slong j, exp; for (j = 0; j < F->length; j++) { exp = fmpz_mpoly_get_term_var_exp_si(F, j, i, ctx); if (j == 0) { fmpq_poly_fit_length(res, exp + 1); _fmpq_poly_set_length(res, exp + 1); } fmpz_swap(res->coeffs + exp, F->coeffs + j); } } void ca_condense_field(ca_t res, ca_ctx_t ctx) { ca_field_srcptr field; if (CA_IS_QQ(res, ctx)) return; if (CA_IS_SPECIAL(res)) { if (CA_IS_SIGNED_INF(res)) { ca_t t; *t = *res; t->field &= ~CA_INF; ca_condense_field(t, ctx); t->field |= CA_INF; *res = *t; } return; } field = CA_FIELD(res, ctx); if (CA_FIELD_IS_NF(field)) { /* demote to rational number */ if (nf_elem_is_rational(CA_NF_ELEM(res), CA_FIELD_NF(field))) { fmpq_t t; fmpq_init(t); if (CA_FIELD_NF(field)->flag & NF_LINEAR) { fmpz_swap(fmpq_numref(t), LNF_ELEM_NUMREF(CA_NF_ELEM(res))); fmpz_swap(fmpq_denref(t), LNF_ELEM_DENREF(CA_NF_ELEM(res))); } else if (CA_FIELD_NF(field)->flag & NF_QUADRATIC) { fmpz_swap(fmpq_numref(t), QNF_ELEM_NUMREF(CA_NF_ELEM(res))); fmpz_swap(fmpq_denref(t), QNF_ELEM_DENREF(CA_NF_ELEM(res))); } else { if (NF_ELEM(CA_NF_ELEM(res))->length != 0) { fmpz_swap(fmpq_numref(t), NF_ELEM(CA_NF_ELEM(res))->coeffs); fmpz_swap(fmpq_denref(t), NF_ELEM(CA_NF_ELEM(res))->den); } } _ca_make_fmpq(res, ctx); fmpq_swap(CA_FMPQ(res), t); fmpq_clear(t); } } else { /* todo: demote to smaller field (in particular, single generator) */ if (fmpz_mpoly_q_is_fmpq(CA_MPOLY_Q(res), CA_FIELD_MCTX(field, ctx))) { fmpq_t t; fmpq_init(t); if (!fmpz_mpoly_q_is_zero(CA_MPOLY_Q(res), CA_FIELD_MCTX(field, ctx))) { fmpz_swap(fmpq_numref(t), fmpz_mpoly_q_numref(CA_MPOLY_Q(res))->coeffs); fmpz_swap(fmpq_denref(t), fmpz_mpoly_q_denref(CA_MPOLY_Q(res))->coeffs); } _ca_make_fmpq(res, ctx); fmpq_swap(CA_FMPQ(res), t); fmpq_clear(t); } else { slong i, nvars, count; int * used; TMP_INIT; nvars = CA_FIELD_MCTX(field, ctx)->minfo->nvars; TMP_START; used = TMP_ALLOC(sizeof(int) * nvars); fmpz_mpoly_q_used_vars(used, CA_MPOLY_Q(res), CA_FIELD_MCTX(field, ctx)); count = 0; for (i = 0; i < nvars; i++) count += used[i]; if (count == 1) { for (i = 0; i < nvars; i++) { if (used[i]) { /* Convert mpoly_q to nf elem (todo -- move to fmpz_mpoly_q module) */ if (CA_EXT_IS_QQBAR(CA_FIELD_EXT_ELEM(field, i))) { ca_field_ptr new_field; fmpq_poly_t P; const fmpz_mpoly_ctx_struct * mctx; fmpz_mpoly_q_struct * F = CA_MPOLY_Q(res); fmpq_poly_init(P); mctx = CA_FIELD_MCTX(field, ctx); new_field = ca_field_cache_lookup_qqbar(CA_CTX_FIELD_CACHE(ctx), CA_EXT_QQBAR(CA_FIELD_EXT_ELEM(field, i)), ctx); if (fmpz_mpoly_is_fmpz(fmpz_mpoly_q_denref(F), mctx)) { _fmpz_mpoly_get_fmpq_poly_var_destructive(P, fmpz_mpoly_q_numref(F), i, mctx); fmpz_swap(P->den, fmpz_mpoly_q_denref(F)->coeffs); _ca_make_field_element(res, new_field, ctx); nf_elem_set_fmpq_poly(CA_NF_ELEM(res), P, CA_FIELD_NF(new_field)); } else if (fmpz_mpoly_is_fmpz(fmpz_mpoly_q_numref(F), mctx)) { _fmpz_mpoly_get_fmpq_poly_var_destructive(P, fmpz_mpoly_q_denref(F), i, mctx); fmpz_swap(P->den, fmpz_mpoly_q_numref(F)->coeffs); if (fmpz_sgn(P->den) < 0) { _fmpz_vec_neg(P->coeffs, P->coeffs, P->length); fmpz_neg(P->den, P->den); } _ca_make_field_element(res, new_field, ctx); nf_elem_set_fmpq_poly(CA_NF_ELEM(res), P, CA_FIELD_NF(new_field)); nf_elem_inv(CA_NF_ELEM(res), CA_NF_ELEM(res), CA_FIELD_NF(new_field)); } else { fmpq_poly_t Q; nf_elem_t t; fmpq_poly_init(Q); nf_elem_init(t, CA_FIELD_NF(new_field)); _fmpz_mpoly_get_fmpq_poly_var_destructive(P, fmpz_mpoly_q_numref(F), i, mctx); _fmpz_mpoly_get_fmpq_poly_var_destructive(Q, fmpz_mpoly_q_denref(F), i, mctx); _ca_make_field_element(res, new_field, ctx); nf_elem_set_fmpq_poly(CA_NF_ELEM(res), P, CA_FIELD_NF(new_field)); nf_elem_set_fmpq_poly(t, Q, CA_FIELD_NF(new_field)); nf_elem_div(CA_NF_ELEM(res), CA_NF_ELEM(res), t, CA_FIELD_NF(new_field)); fmpq_poly_clear(Q); nf_elem_clear(t, CA_FIELD_NF(new_field)); } fmpq_poly_clear(P); } break; } } } TMP_END; } } } calcium-0.4.1/ca/conj.c000066400000000000000000000262131407704557200146300ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" #include "ca_vec.h" void ca_conj_shallow(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { ca_unknown(res, ctx); } else if (CA_IS_QQ(x, ctx)) { ca_set(res, x, ctx); } else if (CA_IS_QQ_I(x, ctx)) { ca_set(res, x, ctx); fmpz_neg(QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1, QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1); } else { _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Conjugate, x), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } } /* todo */ ca_field_ptr ca_ctx_get_field_qqbar(ca_ctx_t ctx, const qqbar_t x); /* Set res to the generator of Q(ext). */ void ca_set_ext(ca_t res, ca_ext_srcptr ext, ca_ctx_t ctx) { if (CA_EXT_HEAD(ext) == CA_QQBar) { ca_field_srcptr field; field = ca_ctx_get_field_qqbar(ctx, CA_EXT_QQBAR(ext)); _ca_make_field_element(res, field, ctx); nf_elem_gen(CA_NF_ELEM(res), CA_FIELD_NF(field)); } else { /* todo: direct function */ ca_field_ptr K; ca_ext_struct * X[1]; X[0] = (ca_ext_ptr) ext; K = ca_field_cache_insert_ext(CA_CTX_FIELD_CACHE(ctx), X, 1, ctx); _ca_make_field_element(res, K, ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } } void ca_conj_ext(ca_t res, ca_ext_ptr ext, ca_ctx_t ctx) { slong p; ulong q; switch (CA_EXT_HEAD(ext)) { case CA_QQBar: if (qqbar_is_real(CA_EXT_QQBAR(ext))) { ca_set_ext(res, ext, ctx); } else if (qqbar_is_i(CA_EXT_QQBAR(ext))) { ca_neg_i(res, ctx); } else if (qqbar_sgn_re(CA_EXT_QQBAR(ext)) == 0) { /* Imaginary number: conjugation is negation */ ca_field_srcptr field; field = ca_ctx_get_field_qqbar(ctx, CA_EXT_QQBAR(ext)); _ca_make_field_element(res, field, ctx); nf_elem_gen(CA_NF_ELEM(res), CA_FIELD_NF(field)); nf_elem_neg(CA_NF_ELEM(res), CA_NF_ELEM(res), CA_FIELD_NF(field)); } else if (qqbar_is_root_of_unity(&p, &q, CA_EXT_QQBAR(ext))) { ca_field_srcptr field; nf_struct * nf; field = ca_ctx_get_field_qqbar(ctx, CA_EXT_QQBAR(ext)); nf = CA_FIELD_NF(field); _ca_make_field_element(res, field, ctx); nf_elem_gen(CA_NF_ELEM(res), CA_FIELD_NF(field)); nf_elem_pow(CA_NF_ELEM(res), CA_NF_ELEM(res), q - 1, nf); ca_condense_field(res, ctx); } else { qqbar_t t; qqbar_init(t); qqbar_conj(t, CA_EXT_QQBAR(ext)); ca_set_qqbar(res, t, ctx); qqbar_clear(t); } break; /* Todo: CA_Conjugate, CA_Sign, ...? */ /* Real-valued extensions */ case CA_Pi: case CA_Euler: case CA_Re: case CA_Im: case CA_Abs: case CA_Arg: case CA_Floor: case CA_Ceil: ca_set_ext(res, ext, ctx); break; /* Functions with branch cuts */ /* Todo: negate things that are pure imaginary */ /* Todo: reevaluate functions (they may want to insert new objects in the field)? */ case CA_Sqrt: case CA_Log: case CA_LogGamma: if (ca_check_is_negative_real(CA_EXT_FUNC_ARGS(ext), ctx) != T_FALSE) { ca_set_ext(res, ext, ctx); ca_conj_shallow(res, res, ctx); } else if (ca_check_is_real(CA_EXT_FUNC_ARGS(ext), ctx) == T_TRUE) { ca_set_ext(res, ext, ctx); } else { ca_t t; ca_init(t, ctx); ca_conj_deep(t, CA_EXT_FUNC_ARGS(ext), ctx); _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_EXT_HEAD(ext), t), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); ca_clear(t, ctx); } break; case CA_Pow: if (ca_check_is_negative_real(CA_EXT_FUNC_ARGS(ext) + 0, ctx) != T_FALSE) { ca_set_ext(res, ext, ctx); ca_conj_shallow(res, res, ctx); } else if (ca_check_is_real(CA_EXT_FUNC_ARGS(ext) + 0, ctx) == T_TRUE && ca_check_is_real(CA_EXT_FUNC_ARGS(ext) + 1, ctx) == T_TRUE) { ca_set_ext(res, ext, ctx); } else { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); ca_conj_deep(t, CA_EXT_FUNC_ARGS(ext) + 0, ctx); ca_conj_deep(u, CA_EXT_FUNC_ARGS(ext) + 1, ctx); _ca_make_field_element(res, _ca_ctx_get_field_fxy(ctx, CA_Pow, t, u), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); ca_clear(t, ctx); ca_clear(u, ctx); } break; /* Meromorphic functions: conjugate argument */ /* Todo: negate things that are pure imaginary */ /* Todo: reevaluate functions (they may want to insert new objects in the field)? */ case CA_Exp: case CA_Sin: case CA_Cos: case CA_Tan: case CA_Cosh: case CA_Sinh: case CA_Tanh: case CA_Gamma: case CA_RiemannZeta: case CA_Erf: case CA_Erfc: case CA_Erfi: { if (ca_check_is_real(CA_EXT_FUNC_ARGS(ext), ctx) == T_TRUE) { ca_set_ext(res, ext, ctx); } else { ca_t t; ca_init(t, ctx); ca_conj_deep(t, CA_EXT_FUNC_ARGS(ext), ctx); _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_EXT_HEAD(ext), t), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); ca_clear(t, ctx); } } break; default: ca_set_ext(res, ext, ctx); ca_conj_shallow(res, res, ctx); } } /* Complex conjugate assuming that the generator is pure imaginary. */ void nf_elem_conj_imag(nf_elem_t a, const nf_elem_t b, const nf_t nf) { nf_elem_set(a, b, nf); if (nf->flag & NF_LINEAR) { } else if (nf->flag & NF_QUADRATIC) { fmpz_neg(QNF_ELEM_NUMREF(a) + 1, QNF_ELEM_NUMREF(a) + 1); } else { slong i; for (i = 1; i < NF_ELEM(a)->length; i += 2) fmpz_neg(NF_ELEM(a)->coeffs + i, NF_ELEM(a)->coeffs + i); } } void ca_conj_deep(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { /* todo */ ca_unknown(res, ctx); } else if (CA_IS_QQ(x, ctx)) { ca_set(res, x, ctx); } else if (CA_IS_QQ_I(x, ctx)) { ca_set(res, x, ctx); fmpz_neg(QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1, QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1); } else { ca_field_ptr K; slong p; ulong q; K = CA_FIELD(x, ctx); if (CA_FIELD_IS_NF(K)) { if (qqbar_is_real(CA_EXT_QQBAR(CA_FIELD_EXT_ELEM(K, 0)))) { ca_set(res, x, ctx); } else if (qqbar_sgn_re(CA_EXT_QQBAR(CA_FIELD_EXT_ELEM(K, 0))) == 0) { ca_set(res, x, ctx); nf_elem_conj_imag(CA_NF_ELEM(res), CA_NF_ELEM(res), CA_FIELD_NF(K)); } else if (ca_is_cyclotomic_nf_elem(&p, &q, x, ctx)) { nf_struct * nf; fmpq_poly_t poly; nf = CA_FIELD_NF(CA_FIELD(x, ctx)); fmpq_poly_init(poly); nf_elem_get_fmpq_poly(poly, CA_NF_ELEM(x), nf); ca_set(res, x, ctx); nf_elem_gen(CA_NF_ELEM(res), nf); nf_elem_pow(CA_NF_ELEM(res), CA_NF_ELEM(res), q - 1, nf); ca_condense_field(res, ctx); ca_fmpq_poly_evaluate(res, poly, res, ctx); fmpq_poly_clear(poly); } else { /* Todo: when to conjugate the extension number directly? We call ca_set_qqbar because it might do some rewriting that is actually desirable, e.g. standardizing in cyclotomic fields. This means that we can't safely just copy the nf_elems, because the field representation could be different. */ fmpq_poly_t poly; qqbar_t t; qqbar_init(t); fmpq_poly_init(poly); nf_elem_get_fmpq_poly(poly, CA_NF_ELEM(x), CA_FIELD_NF(K)); qqbar_conj(t, CA_EXT_QQBAR(CA_FIELD_EXT_ELEM(K, 0))); ca_set_qqbar(res, t, ctx); ca_fmpq_poly_evaluate(res, poly, res, ctx); qqbar_clear(t); fmpq_poly_clear(poly); } } else { slong nvars; int * used; slong i; ca_ptr cext; nvars = CA_FIELD_LENGTH(K); used = flint_calloc(nvars, sizeof(int)); cext = _ca_vec_init(nvars, ctx); fmpz_mpoly_q_used_vars(used, CA_MPOLY_Q(x), CA_FIELD_MCTX(K, ctx)); for (i = 0; i < nvars; i++) { if (used[i]) { ca_conj_ext(cext + i, CA_FIELD_EXT_ELEM(K, i), ctx); } } /* todo: somehow exploit the fact that the denominator is guaranteed to be nonzero, meaning that doesn't need to be checked? */ ca_fmpz_mpoly_q_evaluate(res, CA_MPOLY_Q(x), cext, CA_FIELD_MCTX(K, ctx), ctx); _ca_vec_clear(cext, nvars, ctx); flint_free(used); } } } void ca_conj(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { /* todo */ ca_unknown(res, ctx); } else if (CA_IS_QQ(x, ctx)) { ca_set(res, x, ctx); } else if (CA_IS_QQ_I(x, ctx)) { ca_set(res, x, ctx); fmpz_neg(QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1, QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1); } /* todo: avoid duplicate computations with is_real/is_imaginary */ else if (ca_check_is_real(x, ctx) == T_TRUE) { ca_set(res, x, ctx); } else if (ca_check_is_imaginary(x, ctx) == T_TRUE) { ca_neg(res, x, ctx); } else { ca_conj_deep(res, x, ctx); } } calcium-0.4.1/ca/csgn.c000066400000000000000000000036621407704557200146340ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" /* todo: better impl */ /* may want to return symbolic csgn (can still bound numerically) */ void ca_csgn(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t re, im, zero; truth_t is_zero; if (CA_IS_SPECIAL(x)) { if (ca_check_is_signed_inf(x, ctx) == T_TRUE) { ca_sgn(res, x, ctx); ca_csgn(res, res, ctx); } else if (ca_check_is_uinf(x, ctx) == T_TRUE || ca_check_is_undefined(x, ctx) == T_TRUE) { ca_undefined(res, ctx); } else { ca_unknown(res, ctx); } return; } is_zero = ca_check_is_zero(x, ctx); if (is_zero == T_TRUE) { ca_zero(res, ctx); return; } if (is_zero == T_UNKNOWN) { ca_unknown(res, ctx); return; } ca_init(re, ctx); ca_init(zero, ctx); ca_re(re, x, ctx); if (ca_check_gt(re, zero, ctx) == T_TRUE) { ca_one(res, ctx); } else if (ca_check_lt(re, zero, ctx) == T_TRUE) { ca_neg_one(res, ctx); } else if (ca_check_is_zero(re, ctx) == T_TRUE) { ca_init(im, ctx); ca_im(im, x, ctx); if (ca_check_gt(im, zero, ctx) == T_TRUE) { ca_one(res, ctx); } else if (ca_check_lt(im, zero, ctx) == T_TRUE) { ca_neg_one(res, ctx); } else { ca_unknown(res, ctx); } ca_clear(im, ctx); } else { ca_unknown(res, ctx); } ca_clear(re, ctx); } calcium-0.4.1/ca/ctx_clear.c000066400000000000000000000016631407704557200156450ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" void ca_ctx_clear(ca_ctx_t ctx) { slong i; CA_INFO(ctx, ("%wd extension numbers cached at time of destruction\n", CA_CTX_EXT_CACHE(ctx)->length)); CA_INFO(ctx, ("%wd fields cached at time of destruction\n", CA_CTX_FIELD_CACHE(ctx)->length)); ca_ext_cache_clear(CA_CTX_EXT_CACHE(ctx), ctx); ca_field_cache_clear(CA_CTX_FIELD_CACHE(ctx), ctx); for (i = 0; i < ctx->mctx_len; i++) flint_free(ctx->mctx[i]); flint_free(ctx->mctx); flint_free(ctx->options); } calcium-0.4.1/ca/ctx_get_field_const.c000066400000000000000000000015441407704557200177050ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" ca_field_ptr _ca_ctx_get_field_const(ca_ctx_t ctx, calcium_func_code func) { ca_ext_t ext; ca_ext_struct * ext_ptr[1]; ca_field_ptr field; /* todo: shallow copy */ ca_ext_init_const(ext, func, ctx); ext_ptr[0] = ca_ext_cache_insert(CA_CTX_EXT_CACHE(ctx), ext, ctx); field = ca_field_cache_insert_ext(CA_CTX_FIELD_CACHE(ctx), ext_ptr, 1, ctx); ca_ext_clear(ext, ctx); return field; } calcium-0.4.1/ca/ctx_get_field_fx.c000066400000000000000000000015571407704557200172000ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" ca_field_ptr _ca_ctx_get_field_fx(ca_ctx_t ctx, calcium_func_code func, const ca_t x) { ca_ext_t ext; ca_ext_struct * ext_ptr[1]; ca_field_ptr field; /* todo: shallow copy */ ca_ext_init_fx(ext, func, x, ctx); ext_ptr[0] = ca_ext_cache_insert(CA_CTX_EXT_CACHE(ctx), ext, ctx); field = ca_field_cache_insert_ext(CA_CTX_FIELD_CACHE(ctx), ext_ptr, 1, ctx); ca_ext_clear(ext, ctx); return field; } calcium-0.4.1/ca/ctx_get_field_fxy.c000066400000000000000000000016021407704557200173600ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" ca_field_ptr _ca_ctx_get_field_fxy(ca_ctx_t ctx, calcium_func_code func, const ca_t x, const ca_t y) { ca_ext_t ext; ca_ext_struct * ext_ptr[1]; ca_field_ptr field; /* todo: shallow copy */ ca_ext_init_fxy(ext, func, x, y, ctx); ext_ptr[0] = ca_ext_cache_insert(CA_CTX_EXT_CACHE(ctx), ext, ctx); field = ca_field_cache_insert_ext(CA_CTX_FIELD_CACHE(ctx), ext_ptr, 1, ctx); ca_ext_clear(ext, ctx); return field; } calcium-0.4.1/ca/ctx_init.c000066400000000000000000000035401407704557200155160ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" void ca_ctx_init(ca_ctx_t ctx) { qqbar_t onei; ca_ext_t ext; ca_ext_struct * ext_ptr[1]; ctx->options = flint_calloc(CA_OPT_NUM_OPTIONS, sizeof(slong)); ctx->options[CA_OPT_PREC_LIMIT] = 4096; ctx->options[CA_OPT_QQBAR_DEG_LIMIT] = 120; ctx->options[CA_OPT_LOW_PREC] = 64; ctx->options[CA_OPT_SMOOTH_LIMIT] = 32; ctx->options[CA_OPT_LLL_PREC] = 128; ctx->options[CA_OPT_POW_LIMIT] = 20; ctx->options[CA_OPT_USE_GROEBNER] = 1; ctx->options[CA_OPT_GROEBNER_LENGTH_LIMIT] = 100; ctx->options[CA_OPT_GROEBNER_POLY_LENGTH_LIMIT] = 1000; ctx->options[CA_OPT_GROEBNER_POLY_BITS_LIMIT] = 10000; ctx->options[CA_OPT_VIETA_LIMIT] = 6; ctx->options[CA_OPT_PRINT_FLAGS] = CA_PRINT_DEFAULT; ctx->options[CA_OPT_MPOLY_ORD] = ORD_LEX; ctx->options[CA_OPT_TRIG_FORM] = CA_TRIG_EXPONENTIAL; ctx->mctx = NULL; ctx->mctx_len = 0; ca_ext_cache_init(CA_CTX_EXT_CACHE(ctx), ctx); ca_field_cache_init(CA_CTX_FIELD_CACHE(ctx), ctx); /* Always create QQ */ ctx->field_qq = ca_field_cache_insert_ext(CA_CTX_FIELD_CACHE(ctx), NULL, 0, ctx); /* Always create QQ(i) */ qqbar_init(onei); qqbar_i(onei); ca_ext_init_qqbar(ext, onei, ctx); ext_ptr[0] = ca_ext_cache_insert(CA_CTX_EXT_CACHE(ctx), ext, ctx); ctx->field_qq_i = ca_field_cache_insert_ext(CA_CTX_FIELD_CACHE(ctx), ext_ptr, 1, ctx); qqbar_clear(onei); ca_ext_clear(ext, ctx); } calcium-0.4.1/ca/ctx_print.c000066400000000000000000000014571407704557200157140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" void ca_ctx_print(ca_ctx_t ctx) { slong i; flint_printf("Calcium context with %wd cached fields:\n", CA_CTX_FIELD_CACHE(ctx)->length); for (i = 0; i < CA_CTX_FIELD_CACHE(ctx)->length; i++) { flint_printf("%wd ", i); ca_field_print(CA_CTX_FIELD_CACHE(ctx)->items[i], ctx); flint_printf("\n"); } flint_printf("\n"); } calcium-0.4.1/ca/div.c000066400000000000000000000121421407704557200144550ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_div_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx) { ca_field_srcptr field; if (CA_IS_SPECIAL(x)) { if (CA_IS_SIGNED_INF(x)) { if (fmpq_is_zero(y)) ca_uinf(res, ctx); else if (fmpq_sgn(y) > 0) ca_set(res, x, ctx); else ca_neg(res, x, ctx); } else { ca_set(res, x, ctx); } return; } if (fmpq_is_zero(y)) { truth_t x_zero = ca_check_is_zero(x, ctx); if (x_zero == T_TRUE) ca_undefined(res, ctx); else if (x_zero == T_FALSE) ca_uinf(res, ctx); else ca_unknown(res, ctx); return; } if (CA_IS_QQ(x, ctx)) { _ca_make_fmpq(res, ctx); fmpq_div(CA_FMPQ(res), CA_FMPQ(x), y); return; } else { field = CA_FIELD(x, ctx); _ca_make_field_element(res, field, ctx); if (CA_FIELD_IS_NF(field)) { nf_elem_scalar_div_fmpq(CA_NF_ELEM(res), CA_NF_ELEM(x), y, CA_FIELD_NF(field)); } else { fmpz_mpoly_q_div_fmpq(CA_MPOLY_Q(res), CA_MPOLY_Q(x), y, CA_FIELD_MCTX(field, ctx)); } } } void ca_div_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx) { fmpq_t t; *fmpq_numref(t) = *y; *fmpq_denref(t) = 1; ca_div_fmpq(res, x, t, ctx); } void ca_div_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx) { fmpz_t t; fmpz_init_set_ui(t, y); ca_div_fmpz(res, x, t, ctx); fmpz_clear(t); } void ca_div_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx) { fmpz_t t; fmpz_init_set_si(t, y); ca_div_fmpz(res, x, t, ctx); fmpz_clear(t); } void ca_fmpq_div(ca_t res, const fmpq_t x, const ca_t y, ca_ctx_t ctx) { ca_t t; ca_init(t, ctx); ca_set_fmpq(t, x, ctx); ca_div(res, t, y, ctx); ca_clear(t, ctx); } void ca_fmpz_div(ca_t res, const fmpz_t x, const ca_t y, ca_ctx_t ctx) { ca_t t; ca_init(t, ctx); ca_set_fmpz(t, x, ctx); ca_div(res, t, y, ctx); ca_clear(t, ctx); } void ca_si_div(ca_t res, slong x, const ca_t y, ca_ctx_t ctx) { ca_t t; ca_init(t, ctx); ca_set_si(t, x, ctx); ca_div(res, t, y, ctx); ca_clear(t, ctx); } void ca_ui_div(ca_t res, ulong x, const ca_t y, ca_ctx_t ctx) { ca_t t; ca_init(t, ctx); ca_set_ui(t, x, ctx); ca_div(res, t, y, ctx); ca_clear(t, ctx); } void ca_div(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) { ca_field_srcptr xfield, yfield, zfield; truth_t x_is_zero, y_is_zero; xfield = CA_FIELD(x, ctx); yfield = CA_FIELD(y, ctx); if (CA_IS_QQ(x, ctx) && (xfield == yfield)) { if (fmpq_is_zero(CA_FMPQ(y))) { if (fmpq_is_zero(CA_FMPQ(x))) ca_undefined(res, ctx); else ca_uinf(res, ctx); } else { _ca_make_fmpq(res, ctx); fmpq_div(CA_FMPQ(res), CA_FMPQ(x), CA_FMPQ(y)); } return; } if (CA_IS_QQ(y, ctx)) { if (res == y) { fmpq_t t; fmpq_init(t); fmpq_set(t, CA_FMPQ(y)); ca_div_fmpq(res, x, t, ctx); fmpq_clear(t); } else { ca_div_fmpq(res, x, CA_FMPQ(y), ctx); } return; } if (CA_IS_SPECIAL(x) || CA_IS_SPECIAL(y)) { ca_t t; ca_init(t, ctx); ca_inv(t, y, ctx); ca_mul(res, x, t, ctx); ca_clear(t, ctx); return; } y_is_zero = ca_check_is_zero(y, ctx); if (y_is_zero == T_TRUE) { x_is_zero = ca_check_is_zero(x, ctx); if (x_is_zero == T_FALSE) ca_uinf(res, ctx); else if (x_is_zero == T_TRUE) ca_undefined(res, ctx); else ca_unknown(res, ctx); return; } else if (y_is_zero == T_UNKNOWN) { ca_unknown(res, ctx); return; } if (xfield == yfield) { zfield = xfield; _ca_make_field_element(res, zfield, ctx); if (CA_FIELD_IS_NF(zfield)) { nf_elem_div(CA_NF_ELEM(res), CA_NF_ELEM(x), CA_NF_ELEM(y), CA_FIELD_NF(zfield)); } else { fmpz_mpoly_q_div(CA_MPOLY_Q(res), CA_MPOLY_Q(x), CA_MPOLY_Q(y), CA_FIELD_MCTX(zfield, ctx)); _ca_mpoly_q_reduce_ideal(CA_MPOLY_Q(res), zfield, ctx); _ca_mpoly_q_simplify_fraction_ideal(CA_MPOLY_Q(res), zfield, ctx); } ca_condense_field(res, ctx); return; } { ca_t t; ca_init(t, ctx); ca_inv(t, y, ctx); ca_mul(res, x, t, ctx); ca_clear(t, ctx); } } calcium-0.4.1/ca/dot.c000066400000000000000000000023111407704557200144560ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_dot(ca_t res, const ca_t initial, int subtract, ca_srcptr x, slong xstep, ca_srcptr y, slong ystep, slong len, ca_ctx_t ctx) { slong i; ca_t t; if (len <= 0) { if (initial == NULL) ca_zero(res, ctx); else ca_set(res, initial, ctx); return; } ca_init(t, ctx); if (initial == NULL) { ca_mul(res, x, y, ctx); } else { if (subtract) ca_neg(res, initial, ctx); else ca_set(res, initial, ctx); ca_mul(t, x, y, ctx); ca_add(res, res, t, ctx); } for (i = 1; i < len; i++) { ca_mul(t, x + i * xstep, y + i * ystep, ctx); ca_add(res, res, t, ctx); } if (subtract) ca_neg(res, res, ctx); ca_clear(t, ctx); } calcium-0.4.1/ca/equal_repr.c000066400000000000000000000020501407704557200160270ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int ca_equal_repr(const ca_t x, const ca_t y, ca_ctx_t ctx) { ca_field_ptr field; /* by assumption: cached field objects are unique */ if (x->field != y->field) return 0; if (CA_IS_SPECIAL(x) && !CA_IS_SIGNED_INF(x)) return x->field == y->field; field = CA_FIELD_UNSPECIAL(x, ctx); if (CA_FIELD_IS_QQ(field)) { return fmpq_equal(CA_FMPQ(x), CA_FMPQ(y)); } else if (CA_FIELD_IS_NF(field)) { return nf_elem_equal(CA_NF_ELEM(x), CA_NF_ELEM(y), CA_FIELD_NF(field)); } else { return fmpz_mpoly_q_equal(CA_MPOLY_Q(x), CA_MPOLY_Q(y), CA_FIELD_MCTX(field, ctx)); } } calcium-0.4.1/ca/erf.c000066400000000000000000000024631407704557200144540ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_erf(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { /* todo: other signed infinities */ if (ca_check_is_pos_inf(x, ctx) == T_TRUE) ca_one(res, ctx); else if (ca_check_is_neg_inf(x, ctx) == T_TRUE) ca_neg_one(res, ctx); else if (ca_check_is_pos_i_inf(x, ctx) == T_TRUE) ca_pos_i_inf(res, ctx); else if (ca_check_is_neg_i_inf(x, ctx) == T_TRUE) ca_neg_i_inf(res, ctx); else if (ca_check_is_undefined(x, ctx) == T_TRUE || ca_check_is_uinf(x, ctx) == T_TRUE) ca_undefined(res, ctx); else ca_unknown(res, ctx); return; } if (ca_check_is_zero(x, ctx) == T_TRUE) { ca_zero(res, ctx); return; } _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Erf, x), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } calcium-0.4.1/ca/erfc.c000066400000000000000000000024671407704557200146230ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_erfc(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { /* todo: other signed infinities */ if (ca_check_is_pos_inf(x, ctx) == T_TRUE) ca_zero(res, ctx); else if (ca_check_is_neg_inf(x, ctx) == T_TRUE) ca_set_ui(res, 2, ctx); else if (ca_check_is_pos_i_inf(x, ctx) == T_TRUE) ca_neg_i_inf(res, ctx); else if (ca_check_is_neg_i_inf(x, ctx) == T_TRUE) ca_pos_i_inf(res, ctx); else if (ca_check_is_undefined(x, ctx) == T_TRUE || ca_check_is_uinf(x, ctx) == T_TRUE) ca_undefined(res, ctx); else ca_unknown(res, ctx); return; } if (ca_check_is_zero(x, ctx) == T_TRUE) { ca_one(res, ctx); return; } _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Erfc, x), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } calcium-0.4.1/ca/erfi.c000066400000000000000000000024551407704557200146260ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_erfi(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { /* todo: other signed infinities */ if (ca_check_is_pos_inf(x, ctx) == T_TRUE) ca_pos_inf(res, ctx); else if (ca_check_is_neg_inf(x, ctx) == T_TRUE) ca_neg_inf(res, ctx); else if (ca_check_is_pos_i_inf(x, ctx) == T_TRUE) ca_i(res, ctx); else if (ca_check_is_neg_i_inf(x, ctx) == T_TRUE) ca_neg_i(res, ctx); else if (ca_check_is_undefined(x, ctx) == T_TRUE || ca_check_is_uinf(x, ctx) == T_TRUE) ca_undefined(res, ctx); else ca_unknown(res, ctx); return; } if (ca_check_is_zero(x, ctx) == T_TRUE) { ca_zero(res, ctx); return; } _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Erfi, x), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } calcium-0.4.1/ca/euler.c000066400000000000000000000011101407704557200150000ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_euler(ca_t res, ca_ctx_t ctx) { _ca_make_field_element(res, _ca_ctx_get_field_const(ctx, CA_Euler), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } calcium-0.4.1/ca/exp.c000066400000000000000000000221121407704557200144650ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int ca_as_fmpq_pi_i(fmpq_t res, const ca_t x, ca_ctx_t ctx) { ca_field_ptr K; ca_t t; int found; if (CA_IS_SPECIAL(x)) return 0; K = CA_FIELD(x, ctx); if (CA_FIELD_IS_QQ(K) || CA_FIELD_IS_NF(K)) return 0; ca_init(t, ctx); ca_pi_i(t, ctx); ca_div(t, x, t, ctx); if (CA_IS_QQ(t, ctx)) { fmpq_set(res, CA_FMPQ(t)); found = 1; } else { found = 0; } ca_clear(t, ctx); return found; } ca_ext_ptr ca_is_fmpq_times_gen_as_ext(fmpq_t c, const ca_t x, ca_ctx_t ctx) { ca_field_ptr K; if (CA_IS_SPECIAL(x)) return NULL; K = CA_FIELD(x, ctx); if (CA_FIELD_IS_QQ(K)) return NULL; /* todo */ if (CA_FIELD_IS_NF(K)) return NULL; if (fmpz_mpoly_is_fmpz(fmpz_mpoly_q_denref(CA_MPOLY_Q(x)), CA_FIELD_MCTX(K, ctx))) { if (fmpz_mpoly_length(fmpz_mpoly_q_numref(CA_MPOLY_Q(x)), CA_FIELD_MCTX(K, ctx)) == 1) { fmpz_mpoly_q_t t; fmpz_t one; /* hack! */ *t = *CA_MPOLY_Q(x); *one = 1; fmpz_mpoly_q_numref(t)->coeffs = one; fmpz_mpoly_q_denref(t)->coeffs = one; if (fmpz_mpoly_is_gen(fmpz_mpoly_q_numref(t), -1, CA_FIELD_MCTX(K, ctx))) { slong i; fmpz_set(fmpq_numref(c), fmpz_mpoly_q_numref(CA_MPOLY_Q(x))->coeffs); fmpz_set(fmpq_denref(c), fmpz_mpoly_q_denref(CA_MPOLY_Q(x))->coeffs); for (i = 0; ; i++) if (fmpz_mpoly_is_gen(fmpz_mpoly_q_numref(t), i, CA_FIELD_MCTX(K, ctx))) return CA_FIELD_EXT_ELEM(K, i); } } } return NULL; } void ca_exp(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_ext_ptr ext; if (CA_IS_SPECIAL(x)) { /* todo: complex signed infinity -> 0, undefined, uinf */ if (ca_check_is_pos_inf(x, ctx) == T_TRUE) ca_pos_inf(res, ctx); else if (ca_check_is_neg_inf(x, ctx) == T_TRUE) ca_zero(res, ctx); else if (ca_check_is_undefined(x, ctx) == T_TRUE || ca_check_is_uinf(x, ctx) == T_TRUE) ca_undefined(res, ctx); else ca_unknown(res, ctx); return; } ext = ca_is_gen_as_ext(x, ctx); /* exp(log(z)) = z */ if (ext != NULL && CA_EXT_HEAD(ext) == CA_Log) { ca_set(res, CA_EXT_FUNC_ARGS(ext), ctx); return; } /* exp((p/q)*log(z)) = z^(p/q) */ /* todo: when to rewrite any exp(a*log(b)) -> b^a? */ { fmpq_t t; fmpq_init(t); ext = ca_is_fmpq_times_gen_as_ext(t, x, ctx); if (ext != NULL && CA_EXT_HEAD(ext) == CA_Log) { ca_pow_fmpq(res, CA_EXT_FUNC_ARGS(ext), t, ctx); fmpq_clear(t); return; } fmpq_clear(t); } if (ca_check_is_zero(x, ctx) == T_TRUE) { ca_one(res, ctx); return; } /* exp(p/q*pi*i) -> root of unity */ { fmpq_t t; fmpq_init(t); if (ca_as_fmpq_pi_i(t, x, ctx)) { if (fmpz_cmp_ui(fmpq_denref(t), ctx->options[CA_OPT_QQBAR_DEG_LIMIT]) <= 0) { slong p, q; qqbar_t a; q = fmpz_get_ui(fmpq_denref(t)); p = fmpz_fdiv_ui(fmpq_numref(t), 2 * q); if (q == 1) { if (p == 0) ca_one(res, ctx); else ca_neg_one(res, ctx); } else if (q == 2) { if (p == 1) ca_i(res, ctx); else ca_neg_i(res, ctx); } else { qqbar_init(a); qqbar_exp_pi_i(a, 1, q); ca_set_qqbar(res, a, ctx); ca_pow_ui(res, res, p, ctx); qqbar_clear(a); } fmpq_clear(t); return; } } fmpq_clear(t); } /* exp((p1/q1)*log(z1) + ... + S) = z1^(p1/q1) * ... * exp(S) */ { if (CA_FIELD_IS_GENERIC(CA_FIELD(x, ctx))) { fmpz_mpoly_ctx_struct * mctx; fmpz_mpoly_q_struct * rat; ca_field_ptr K; slong i, j, numer_len, field_len, ok, have_log, log_index; ulong * exp; K = CA_FIELD(x, ctx); field_len = CA_FIELD_LENGTH(K); mctx = CA_FIELD_MCTX(K, ctx); rat = CA_MPOLY_Q(x); exp = flint_malloc(field_len * sizeof(ulong)); /* todo: handle more complex cases (partial fraction decomposition?) */ if (fmpz_mpoly_is_fmpz(fmpz_mpoly_q_denref(rat), mctx)) { numer_len = fmpz_mpoly_length(fmpz_mpoly_q_numref(rat), mctx); for (i = 0; i < numer_len; i++) { if (fmpz_mpoly_term_exp_fits_ui(fmpz_mpoly_q_numref(rat), i, mctx)) { fmpz_mpoly_get_term_exp_ui(exp, fmpz_mpoly_q_numref(rat), i, mctx); ok = 1; have_log = 0; log_index = 0; for (j = 0; j < field_len; j++) { if (exp[j] != 0 && (have_log || exp[j] > 1 || CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, j)) != CA_Log)) { ok = 0; break; } if (exp[j] == 1 && CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, j)) == CA_Log) { have_log = 1; log_index = j; continue; } } if (ok && have_log) { ca_t x_deflated, power; ca_init(x_deflated, ctx); ca_init(power, ctx); _ca_make_field_element(x_deflated, K, ctx); fmpz_mpoly_get_term(fmpz_mpoly_q_numref(CA_MPOLY_Q(x_deflated)), fmpz_mpoly_q_numref(rat), i, mctx); fmpz_mpoly_sub(fmpz_mpoly_q_numref(CA_MPOLY_Q(x_deflated)), fmpz_mpoly_q_numref(rat), fmpz_mpoly_q_numref(CA_MPOLY_Q(x_deflated)), mctx); fmpz_mpoly_set(fmpz_mpoly_q_denref(CA_MPOLY_Q(x_deflated)), fmpz_mpoly_q_denref(rat), mctx); fmpz_mpoly_q_canonicalise(CA_MPOLY_Q(x_deflated), mctx); _ca_mpoly_q_reduce_ideal(CA_MPOLY_Q(x_deflated), K, ctx); ca_condense_field(x_deflated, ctx); ca_set_fmpz(power, fmpz_mpoly_q_numref(rat)->coeffs + i, ctx); ca_div_fmpz(power, power, fmpz_mpoly_q_denref(rat)->coeffs, ctx); ca_pow(power, CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, log_index)), power, ctx); ca_exp(x_deflated, x_deflated, ctx); ca_mul(res, power, x_deflated, ctx); ca_clear(x_deflated, ctx); ca_clear(power, ctx); flint_free(exp); return; } } } } flint_free(exp); } } /* Could be optional: csgn normalization */ if (0) { ca_t t; ca_init(t, ctx); ca_sgn(t, x, ctx); if (ca_check_is_neg_one(t, ctx) == T_TRUE) { ca_neg(t, x, ctx); _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Exp, t), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); fmpz_mpoly_q_inv(CA_MPOLY_Q(res), CA_MPOLY_Q(res), CA_MCTX_1(ctx)); _ca_mpoly_q_reduce_ideal(CA_MPOLY_Q(res), CA_FIELD(res, ctx), ctx); ca_condense_field(res, ctx); } else { _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Exp, x), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); _ca_mpoly_q_reduce_ideal(CA_MPOLY_Q(res), CA_FIELD(res, ctx), ctx); ca_condense_field(res, ctx); } return; } _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Exp, x), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); _ca_mpoly_q_reduce_ideal(CA_MPOLY_Q(res), CA_FIELD(res, ctx), ctx); ca_condense_field(res, ctx); } calcium-0.4.1/ca/factor.c000066400000000000000000000140371407704557200151560ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" /* #if __FLINT_RELEASE >= 20700 */ #if 1 #define HAVE_MPOLY_FAC 1 #else #define HAVE_MPOLY_FAC 0 #endif #if HAVE_MPOLY_FAC #include "flint/fmpz_mpoly_factor.h" #endif void _ca_factor_fmpz(ca_factor_t res, const fmpz_t x, int inv, ulong flags, ca_ctx_t ctx) { slong i; fmpz_factor_t fac; ca_t b, e; if (fmpz_is_one(x)) return; fmpz_factor_init(fac); if (flags & CA_FACTOR_ZZ_FULL) { fmpz_factor(fac, x); } else if (flags & CA_FACTOR_ZZ_SMOOTH) { slong smooth_limit = ctx->options[CA_OPT_SMOOTH_LIMIT]; fmpz_factor_smooth(fac, x, smooth_limit, -1); /* -1 => no primality test */ } else { flint_abort(); } ca_init(b, ctx); ca_init(e, ctx); if (fac->sign != 1) { ca_set_si(b, fac->sign, ctx); ca_one(e, ctx); ca_factor_insert(res, b, e, ctx); } for (i = 0; i < fac->num; i++) { ca_set_fmpz(b, fac->p + i, ctx); ca_set_si(e, inv ? -(slong)(fac->exp[i]) : (fac->exp[i]), ctx); ca_factor_insert(res, b, e, ctx); } fmpz_factor_clear(fac); ca_clear(b, ctx); ca_clear(e, ctx); } void _ca_factor_fmpq(ca_factor_t res, const fmpq_t x, ulong flags, ca_ctx_t ctx) { if (flags & (CA_FACTOR_ZZ_SMOOTH | CA_FACTOR_ZZ_FULL)) { _ca_factor_fmpz(res, fmpq_numref(x), 0, flags, ctx); _ca_factor_fmpz(res, fmpq_denref(x), 1, flags, ctx); } else if (!fmpq_is_one(x)) { ca_t b, e; ca_init(b, ctx); ca_init(e, ctx); ca_set_fmpq(b, x, ctx); ca_one(e, ctx); ca_factor_insert(res, b, e, ctx); ca_clear(b, ctx); ca_clear(e, ctx); } } static int _ca_fmpz_mpoly_factor(fmpz_mpoly_factor_t fac, const fmpz_mpoly_t poly, int full, const fmpz_mpoly_ctx_t ctx) { if (full) return fmpz_mpoly_factor(fac, poly, ctx); else return fmpz_mpoly_factor_squarefree(fac, poly, ctx); } void ca_factor(ca_factor_t res, const ca_t x, ulong flags, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { flint_printf("ca_factor: expected a non-special value\n"); flint_abort(); } ca_factor_one(res, ctx); if (CA_IS_QQ(x, ctx)) { _ca_factor_fmpq(res, CA_FMPQ(x), flags, ctx); return; } /* todo: factoring in number fields */ if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { ca_t e; ca_init(e, ctx); ca_one(e, ctx); ca_factor_insert(res, x, e, ctx); ca_clear(e, ctx); return; } { if (flags & (CA_FACTOR_POLY_CONTENT | CA_FACTOR_POLY_SQF | CA_FACTOR_POLY_FULL)) { const fmpz_mpoly_ctx_struct * mctx; ca_t b, e; fmpq_t content; mctx = CA_FIELD_MCTX(CA_FIELD(x, ctx), ctx); fmpq_init(content); ca_init(b, ctx); ca_init(e, ctx); #if HAVE_MPOLY_FAC if (flags & (CA_FACTOR_POLY_SQF | CA_FACTOR_POLY_FULL)) { int full; slong i; fmpz_mpoly_factor_t mfac; full = (flags & CA_FACTOR_POLY_FULL) ? 1 : 0; fmpz_mpoly_factor_init(mfac, mctx); if (!_ca_fmpz_mpoly_factor(mfac, fmpz_mpoly_q_numref(CA_MPOLY_Q(x)), full, mctx)) { flint_printf("ca_factor: unable to factor numerator\n"); flint_abort(); } for (i = 0; i < mfac->num; i++) { ca_set_fmpz(e, mfac->exp + i, ctx); _ca_make_field_element(b, CA_FIELD(x, ctx), ctx); fmpz_mpoly_swap(fmpz_mpoly_q_numref(CA_MPOLY_Q(b)), mfac->poly + i, mctx); fmpz_mpoly_one(fmpz_mpoly_q_denref(CA_MPOLY_Q(b)), mctx); ca_factor_insert(res, b, e, ctx); } fmpz_set(fmpq_numref(content), mfac->constant); fmpz_mpoly_factor_clear(mfac, mctx); fmpz_mpoly_factor_init(mfac, mctx); if (!_ca_fmpz_mpoly_factor(mfac, fmpz_mpoly_q_denref(CA_MPOLY_Q(x)), full, mctx)) { flint_printf("ca_factor: unable to factor denominator\n"); flint_abort(); } for (i = 0; i < mfac->num; i++) { ca_set_fmpz(e, mfac->exp + i, ctx); ca_neg(e, e, ctx); _ca_make_field_element(b, CA_FIELD(x, ctx), ctx); fmpz_mpoly_swap(fmpz_mpoly_q_numref(CA_MPOLY_Q(b)), mfac->poly + i, mctx); fmpz_mpoly_one(fmpz_mpoly_q_denref(CA_MPOLY_Q(b)), mctx); ca_factor_insert(res, b, e, ctx); } fmpz_set(fmpq_denref(content), mfac->constant); fmpz_mpoly_factor_clear(mfac, mctx); } else #endif { fmpz_mpoly_q_content(content, CA_MPOLY_Q(x), mctx); ca_div_fmpq(b, x, content, ctx); ca_one(e, ctx); ca_factor_insert(res, b, e, ctx); } if (fmpz_sgn(fmpq_denref(content)) < 0) { fmpz_neg(fmpq_numref(content), fmpq_numref(content)); fmpz_neg(fmpq_denref(content), fmpq_denref(content)); } _ca_factor_fmpq(res, content, flags, ctx); ca_clear(b, ctx); ca_clear(e, ctx); fmpq_clear(content); } else { ca_t e; ca_init(e, ctx); ca_one(e, ctx); ca_factor_insert(res, x, e, ctx); ca_clear(e, ctx); } } } calcium-0.4.1/ca/factor_clear.c000066400000000000000000000011531407704557200163170ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_vec.h" void ca_factor_clear(ca_factor_t fac, ca_ctx_t ctx) { if (fac->alloc != 0) { _ca_vec_clear(fac->base, fac->alloc, ctx); _ca_vec_clear(fac->exp, fac->alloc, ctx); } } calcium-0.4.1/ca/factor_get_ca.c000066400000000000000000000016561407704557200164630ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_factor_get_ca(ca_t res, const ca_factor_t fac, ca_ctx_t ctx) { slong i, len; ca_t t; len = fac->length; if (len == 0) { ca_one(res, ctx); } else if (len == 1) { ca_pow(res, fac->base, fac->exp, ctx); } else { ca_init(t, ctx); ca_pow(res, fac->base, fac->exp, ctx); for (i = 1; i < len; i++) { ca_pow(t, fac->base + i, fac->exp + i, ctx); ca_mul(res, res, t, ctx); } ca_clear(t, ctx); } } calcium-0.4.1/ca/factor_init.c000066400000000000000000000010401407704557200161670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_factor_init(ca_factor_t fac, ca_ctx_t ctx) { fac->base = NULL; fac->exp = NULL; fac->length = 0; fac->alloc = 0; } calcium-0.4.1/ca/factor_insert.c000066400000000000000000000024201407704557200165330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_factor_insert(ca_factor_t fac, const ca_t base, const ca_t exp, ca_ctx_t ctx) { slong i; for (i = 0; i < fac->length; i++) { if (ca_equal_repr(fac->base + i, base, ctx)) { ca_add(fac->exp, fac->exp, exp, ctx); return; } } if (fac->length == fac->alloc) { slong new_alloc; new_alloc = FLINT_MAX(1, 2 * fac->alloc); fac->base = (ca_ptr) flint_realloc(fac->base, sizeof(ca_struct) * new_alloc); fac->exp = (ca_ptr) flint_realloc(fac->exp, sizeof(ca_struct) * new_alloc); for (i = fac->alloc; i < new_alloc; i++) { ca_init(fac->base + i, ctx); ca_init(fac->exp + i, ctx); } fac->alloc = new_alloc; } ca_set(fac->base + fac->length, base, ctx); ca_set(fac->exp + fac->length, exp, ctx); fac->length++; } calcium-0.4.1/ca/factor_one.c000066400000000000000000000011521407704557200160110ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_factor_one(ca_factor_t fac, ca_ctx_t ctx) { slong i; for (i = 0; i < fac->length; i++) { ca_zero(fac->base + i, ctx); ca_zero(fac->exp + i, ctx); } fac->length = 0; } calcium-0.4.1/ca/factor_print.c000066400000000000000000000012451407704557200163670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_factor_print(const ca_factor_t fac, ca_ctx_t ctx) { slong i; for (i = 0; i < fac->length; i++) { flint_printf("("); ca_print(fac->base + i, ctx); flint_printf(") ^ ("); ca_print(fac->exp + i, ctx); flint_printf(")\n"); } } calcium-0.4.1/ca/floor.c000066400000000000000000000040241407704557200150140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_floor(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (CA_IS_UNKNOWN(x)) ca_unknown(res, ctx); else ca_undefined(res, ctx); return; } if (CA_IS_QQ(x, ctx)) { fmpz_t t; fmpz_init(t); fmpz_fdiv_q(t, CA_FMPQ_NUMREF(x), CA_FMPQ_DENREF(x)); ca_set_fmpz(res, t, ctx); fmpz_clear(t); return; } { slong prec, prec_limit; acb_t v; mag_t m; fmpz_t n; int success = 0; acb_init(v); mag_init(m); fmpz_init(n); prec_limit = ctx->options[CA_OPT_PREC_LIMIT]; prec_limit = FLINT_MAX(prec_limit, 64); for (prec = 64; (prec <= prec_limit) && !success; prec *= 2) { ca_get_acb_raw(v, x, prec, ctx); arb_get_mag(m, acb_realref(v)); if (arb_is_finite(acb_imagref(v)) && mag_cmp_2exp_si(m, prec_limit) <= 0) { arb_floor(acb_realref(v), acb_realref(v), prec); if (arb_get_unique_fmpz(n, acb_realref(v))) { ca_set_fmpz(res, n, ctx); success = 1; break; } } arb_get_mag_lower(m, acb_realref(v)); if (mag_cmp_2exp_si(m, prec_limit) > 0) break; } acb_clear(v); mag_clear(m); fmpz_clear(n); if (success) return; } _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Floor, x), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } calcium-0.4.1/ca/fmpq_poly_evaluate.c000066400000000000000000000031371407704557200175730ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" static void _ca_set_fmpq(ca_t x, const fmpz_t p, const fmpz_t q, ca_ctx_t ctx) { _ca_make_fmpq(x, ctx); fmpz_set(CA_FMPQ_NUMREF(x), p); fmpz_set(CA_FMPQ_DENREF(x), q); } void ca_fmpq_poly_evaluate(ca_t res, const fmpq_poly_t poly, const ca_t x, ca_ctx_t ctx) { if (fmpq_poly_is_zero(poly)) { ca_zero(res, ctx); } else if (fmpq_poly_length(poly) == 1) { _ca_set_fmpq(res, poly->coeffs + 0, poly->den, ctx); } else if (CA_IS_QQ(x, ctx)) { fmpq_t t; fmpq_init(t); fmpq_poly_evaluate_fmpq(t, poly, CA_FMPQ(x)); ca_set_fmpq(res, t, ctx); fmpq_clear(t); } /* todo: fast modular composition for number field elements */ /* else if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) */ else { ca_t t; /* for aliasing */ slong i, n; ca_init(t, ctx); /* todo: rectangular splitting? */ n = fmpq_poly_degree(poly); ca_set_fmpz(t, poly->coeffs + n, ctx); for (i = n - 1; i >= 0; i--) { ca_mul(t, t, x, ctx); ca_add_fmpz(t, t, poly->coeffs + i, ctx); } ca_div_fmpz(res, t, poly->den, ctx); ca_clear(t, ctx); } } calcium-0.4.1/ca/fmpz_mpoly_evaluate.c000066400000000000000000000261501407704557200177610ustar00rootroot00000000000000/* Copyright (C) 2018 Daniel Schultz Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "flint/fmpz_mpoly.h" #include "ca.h" /* The conversion to Horner form can be stated as recursive. However, the call stack has depth proportial to the length of the input polynomial in the worst case. Therefore, we must convert it to an iterative algorithm. The proceedure is HornerForm(f): if f is simple to evaluate return eval(f) else choose a variable v and the smallest non zero exponent e appearing in the terms of f write f = q * v^e + r where r is independent of the variable v return HornerForm(q) * v^e + HornerForm(r) */ typedef struct { slong f; slong r; slong v_var; fmpz_t v_exp; /* will be managed as stack grows / shrinks */ int ret; } stack_entry_struct; typedef stack_entry_struct stack_entry_t[1]; /* A = A * X^pow */ /* todo: cache squares, ...? */ static void _ca_pmul(ca_t A, const ca_t X, const fmpz_t pow, ca_t T, ca_ctx_t ctx) { if (fmpz_is_one(pow)) { ca_mul(A, A, X, ctx); } else { ca_pow_fmpz(T, X, pow, ctx); ca_mul(A, A, T, ctx); } } void ca_fmpz_mpoly_evaluate_horner(ca_t A, const fmpz_mpoly_t B, ca_srcptr C, const fmpz_mpoly_ctx_t ctxB, ca_ctx_t ctx) { int ret; slong nvars = ctxB->minfo->nvars; slong i, j, k, cur, next, f, r, f_prev, r_prev, v; slong sp, rp; stack_entry_struct * stack; ca_struct * regs; ca_t temp; slong * rtypes; ulong totalcounts, maxcounts; ulong * counts; slong Blen = B->length; slong * Blist; const fmpz * Bcoeff = B->coeffs; const ulong * Bexp = B->exps; flint_bitcnt_t Bbits = B->bits; slong BN = mpoly_words_per_exp(Bbits, ctxB->minfo); fmpz * Buexp; fmpz * mdegs; fmpz_t score, tz; TMP_INIT; if (Blen == 0) { ca_zero(A, ctx); return; } if (Blen == 1 && fmpz_mpoly_is_fmpz(B, ctxB)) { ca_set_fmpz(A, B->coeffs, ctx); return; } /* flint_printf("========================== HORNER %wd ==========================\n", Blen); */ FLINT_ASSERT(Blen > 0); TMP_START; fmpz_init(score); fmpz_init(tz); /* unpack B exponents */ Buexp = _fmpz_vec_init(nvars*Blen); for (i = 0; i < Blen; i++) mpoly_get_monomial_ffmpz(Buexp + nvars*i, Bexp + BN*i, Bbits, ctxB->minfo); counts = (ulong *) TMP_ALLOC(nvars*sizeof(ulong)); mdegs = _fmpz_vec_init(nvars); /* stack */ sp = -WORD(1); /* start with empty stack */ stack = (stack_entry_struct *) TMP_ALLOC(nvars*(Blen + 1)*sizeof(stack_entry_struct)); Blist = (slong *) TMP_ALLOC(Blen*sizeof(slong)); /* registers of qqbars */ rp = 0; rtypes = (slong *) TMP_ALLOC((nvars + 1)*sizeof(slong)); regs = (ca_struct *) TMP_ALLOC(nvars*sizeof(ca_struct)); for (i = 0; i < nvars; i++) ca_init(regs + i, ctx); ca_init(temp, ctx); /* polynomials will be stored as link lists */ for (i = 0; i + 1 < Blen; i++) Blist[i] = i + 1; Blist[i] = -WORD(1); sp++; fmpz_init((stack + sp)->v_exp); (stack + sp)->ret = 0; (stack + sp)->f = 0; HornerForm: f = (stack + sp)->f; FLINT_ASSERT(f != -WORD(1)); /* f is not supposed to be zero */ /* obtain a count of the number of terms containing each variable */ for (i = 0; i < nvars; i++) { counts[i] = 0; fmpz_set_si(mdegs + i, -WORD(1)); } for (j = f; j != -WORD(1); j = Blist[j]) { for (i = 0; i < nvars; i++) { if (!fmpz_is_zero(Buexp + nvars*j + i )) { counts[i]++; if (fmpz_sgn(mdegs + i) < 0 || fmpz_cmp(mdegs + i, Buexp + nvars*j + i) > 0) { fmpz_set(mdegs + i, Buexp + nvars*j + i); } } } } totalcounts = 0; maxcounts = 0; v = -WORD(1); for (i = 0; i < nvars; i++) { maxcounts = FLINT_MAX(maxcounts, counts[i]); totalcounts += counts[i]; if (counts[i] != 0) v = i; } /* handle simple cases */ if (totalcounts == 0) { FLINT_ASSERT(Blist[f] == -WORD(1)); /* f should have had only one term */ rtypes[rp] = f; goto HornerFormReturn; } else if (totalcounts == 1) { FLINT_ASSERT(!fmpz_is_zero(Buexp + nvars*f + v)); /* this term should not be a scalar */ ca_pow_fmpz(regs + rp, C + v, Buexp + nvars*f + v, ctx); ca_mul_fmpz(regs + rp, regs + rp, Bcoeff + f, ctx); if (Blist[f] != -WORD(1)) /* if f has a second term */ { /* this term should be a scalar */ FLINT_ASSERT(fmpz_is_zero(Buexp + nvars*Blist[f] + v)); ca_add_fmpz(regs + rp, regs + rp, Bcoeff + Blist[f], ctx); } rtypes[rp] = -WORD(1); goto HornerFormReturn; } /* pick best power to pull out */ k = 0; if (maxcounts == 1) { fmpz_set_si(score, -WORD(1)); for (i = 0; i < nvars; i++) { if (counts[i] == 1 && (fmpz_sgn(score) < 0 || fmpz_cmp(mdegs + i, score) < 0)) { FLINT_ASSERT(fmpz_sgn(mdegs + i) > 0); fmpz_set(score, mdegs + i); k = i; } } } else { fmpz_zero(score); for (i = 0; i < nvars; i++) { if (counts[i] > 1) { FLINT_ASSERT(fmpz_sgn(mdegs + i) > 0); fmpz_mul_ui(tz, mdegs + i, counts[i] - 1); if (fmpz_cmp(tz, score) > 0) { fmpz_swap(score, tz); k = i; } } } } /* set variable power v */ (stack + sp)->v_var = k; fmpz_set((stack + sp)->v_exp, mdegs + k); /* scan f and split into q and v with f = q*v + r then set f = q */ r = -WORD(1); cur = f; f_prev = -WORD(1); r_prev = -WORD(1); while (cur != -WORD(1)) { next = Blist[cur]; if (fmpz_is_zero(Buexp + nvars*cur + k)) { if (f_prev == -WORD(1)) f = Blist[cur]; else Blist[f_prev] = Blist[cur]; if (r_prev == -WORD(1)) r = cur; else Blist[r_prev] = cur; Blist[cur] = -WORD(1); r_prev = cur; } else { /* mdegs[k] should be minimum non zero exponent */ fmpz_sub(Buexp + nvars*cur + k, Buexp + nvars*cur + k, mdegs + k); FLINT_ASSERT(fmpz_sgn(Buexp + nvars*cur + k) >= 0); f_prev = cur; } cur = next; } (stack + sp)->r = r; /* convert the quotient */ sp++; fmpz_init((stack + sp)->v_exp); (stack + sp)->ret = 1; (stack + sp)->f = f; goto HornerForm; HornerForm1: /* convert the remainder */ r = (stack + sp)->r; if (r != -WORD(1)) { /* remainder is non zero */ rp++; FLINT_ASSERT(0 <= rp && rp <= nvars); sp++; fmpz_init((stack + sp)->v_exp); (stack + sp)->ret = 2; (stack + sp)->f = r; goto HornerForm; HornerForm2: if (rtypes[rp - 1] == -WORD(1) && rtypes[rp] == -WORD(1)) { /* both quotient and remainder are polynomials */ _ca_pmul(regs + rp - 1, C + (stack + sp)->v_var, (stack + sp)->v_exp, temp, ctx); ca_add(temp, regs + rp - 1, regs + rp, ctx); ca_swap(temp, regs + rp - 1, ctx); } else if (rtypes[rp - 1] == -WORD(1) && rtypes[rp] != -WORD(1)) { /* quotient is a polynomial, remainder is a scalar */ _ca_pmul(regs + rp - 1, C + (stack + sp)->v_var, (stack + sp)->v_exp, temp, ctx); ca_add_fmpz(regs + rp - 1, regs + rp - 1, Bcoeff + rtypes[rp], ctx); } else if (rtypes[rp - 1] != -WORD(1) && rtypes[rp] == -WORD(1)) { /* quotient is a scalar, remainder is a polynomial */ ca_pow_fmpz(temp, C + (stack + sp)->v_var, (stack + sp)->v_exp, ctx); ca_mul_fmpz(temp, temp, Bcoeff + rtypes[rp - 1], ctx); ca_add(regs + rp - 1, temp, regs + rp, ctx); } else { /* quotient is a scalar, remainder is a scalar */ FLINT_ASSERT(0); /* this should have been handled by simple case */ } rp--; FLINT_ASSERT(0 <= rp && rp <= nvars); } else { /* remainder is zero */ FLINT_ASSERT(rtypes[rp] == -WORD(1)); /* quotient is not a scalar */ /* quotient is a polynomial */ _ca_pmul(regs + rp, C + (stack + sp)->v_var, (stack + sp)->v_exp, temp, ctx); } rtypes[rp] = -WORD(1); HornerFormReturn: ret = (stack + sp)->ret; fmpz_clear((stack + sp)->v_exp); sp--; if (ret == 1) goto HornerForm1; if (ret == 2) goto HornerForm2; FLINT_ASSERT(rp == 0); FLINT_ASSERT(sp == -WORD(1)); if (rtypes[rp] == -WORD(1)) { ca_swap(A, regs + rp, ctx); } else { ca_set_fmpz(A, Bcoeff + rtypes[rp], ctx); } for (i = 0; i < nvars; i++) ca_clear(regs + i, ctx); ca_clear(temp, ctx); fmpz_clear(score); fmpz_clear(tz); _fmpz_vec_clear(mdegs, nvars); _fmpz_vec_clear(Buexp, nvars*Blen); TMP_END; } /* todo: accept fmpz exponents */ void ca_evaluate_fmpz_mpoly_iter(ca_t res, const fmpz_mpoly_t pol, ca_srcptr x, const fmpz_mpoly_ctx_t ctx, ca_ctx_t cactx) { slong i, j, len, nvars; ca_t s, t, u; ulong * exp; len = fmpz_mpoly_length(pol, ctx); if (len == 0) { ca_zero(res, cactx); return; } if (len == 1 && fmpz_mpoly_is_fmpz(pol, ctx)) { ca_set_fmpz(res, pol->coeffs, cactx); return; } nvars = ctx->minfo->nvars; exp = flint_malloc(sizeof(ulong) * nvars); ca_init(s, cactx); ca_init(t, cactx); ca_init(u, cactx); for (i = 0; i < len; i++) { fmpz_mpoly_get_term_exp_ui(exp, pol, i, ctx); ca_one(t, cactx); for (j = 0; j < nvars; j++) { if (exp[j] == 1) { ca_mul(t, t, x + j, cactx); } else if (exp[j] >= 2) { ca_pow_ui(u, x + j, exp[j], cactx); ca_mul(t, t, u, cactx); } } ca_mul_fmpz(t, t, pol->coeffs + i, cactx); ca_add(s, s, t, cactx); } ca_swap(res, s, cactx); flint_free(exp); ca_clear(s, cactx); ca_clear(t, cactx); ca_clear(u, cactx); } void ca_fmpz_mpoly_evaluate(ca_t res, const fmpz_mpoly_t f, ca_srcptr x, const fmpz_mpoly_ctx_t ctx, ca_ctx_t cactx) { ca_fmpz_mpoly_evaluate_horner(res, f, x, ctx, cactx); } calcium-0.4.1/ca/fmpz_mpoly_q_evaluate.c000066400000000000000000000024211407704557200202740ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_fmpz_mpoly_q_evaluate(ca_t res, const fmpz_mpoly_q_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx) { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); ca_fmpz_mpoly_evaluate(t, fmpz_mpoly_q_numref(f), x, mctx, ctx); ca_fmpz_mpoly_evaluate(u, fmpz_mpoly_q_denref(f), x, mctx, ctx); ca_div(res, t, u, ctx); ca_clear(t, ctx); ca_clear(u, ctx); } void ca_fmpz_mpoly_q_evaluate_no_division_by_zero(ca_t res, const fmpz_mpoly_q_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx) { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); ca_fmpz_mpoly_evaluate(t, fmpz_mpoly_q_numref(f), x, mctx, ctx); ca_fmpz_mpoly_evaluate(u, fmpz_mpoly_q_denref(f), x, mctx, ctx); /* todo: write a div function for this */ ca_inv_no_division_by_zero(u, u, ctx); ca_mul(res, t, u, ctx); ca_clear(t, ctx); ca_clear(u, ctx); } calcium-0.4.1/ca/fmpz_poly_evaluate.c000066400000000000000000000025561407704557200176100ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_fmpz_poly_evaluate(ca_t res, const fmpz_poly_t poly, const ca_t x, ca_ctx_t ctx) { if (fmpz_poly_is_zero(poly)) { ca_zero(res, ctx); } else if (fmpz_poly_length(poly) == 1) { ca_set_fmpz(res, poly->coeffs + 0, ctx); } else if (CA_IS_QQ(x, ctx)) { fmpq_t t; fmpq_init(t); fmpz_poly_evaluate_fmpq(t, poly, CA_FMPQ(x)); ca_set_fmpq(res, t, ctx); fmpq_clear(t); } /* todo: fast modular composition for number field elements */ /* else if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) */ else { ca_t t; /* for aliasing */ slong i, n; ca_init(t, ctx); /* todo: rectangular splitting? */ n = fmpz_poly_degree(poly); ca_set_fmpz(t, poly->coeffs + n, ctx); for (i = n - 1; i >= 0; i--) { ca_mul(t, t, x, ctx); ca_add_fmpz(t, t, poly->coeffs + i, ctx); } ca_clear(t, ctx); } } calcium-0.4.1/ca/gamma.c000066400000000000000000000106131407704557200147560ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_gamma_inert(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { flint_abort(); } else { _ca_function_fx(res, CA_Gamma, x, ctx); } } void _ca_gamma_verbatim(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t y, tmp; ca_init(y, ctx); ca_init(tmp, ctx); _ca_function_fx(y, CA_Gamma, x, ctx); ca_merge_fields(tmp, res, x, y, ctx); ca_clear(y, ctx); ca_clear(tmp, ctx); } truth_t ca_re_is_positive(const ca_t x, ca_ctx_t ctx) { ca_t t, u; truth_t res; ca_init(t, ctx); ca_init(u, ctx); ca_re(t, x, ctx); res = ca_check_gt(t, u, ctx); ca_clear(t, ctx); ca_clear(u, ctx); return res; } void ca_gamma(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { /* todo: other signs */ if (ca_check_is_pos_inf(x, ctx)) { ca_pos_inf(res, ctx); } else if (ca_check_is_neg_inf(x, ctx) || ca_check_is_undefined(x, ctx) || ca_check_is_uinf(x, ctx)) { ca_undefined(res, ctx); } else if (ca_check_is_pos_i_inf(x, ctx) || ca_check_is_neg_i_inf(x, ctx)) { ca_zero(res, ctx); } else { ca_unknown(res, ctx); } } else { truth_t is_integer, is_positive; slong expand_limit; expand_limit = ctx->options[CA_OPT_PREC_LIMIT]; is_integer = ca_check_is_integer(x, ctx); if (is_integer == T_TRUE) { is_positive = ca_re_is_positive(x, ctx); if (is_positive == T_TRUE) { fmpz_t t; fmpz_init(t); if (ca_get_fmpz(t, x, ctx) && fmpz_cmp_ui(t, expand_limit) < 0) { fmpz_fac_ui(t, fmpz_get_ui(t) - 1); ca_set_fmpz(res, t, ctx); } else { /* todo: may want to use the potentially simplified x (to an integer) here... */ _ca_gamma_verbatim(res, x, ctx); } fmpz_clear(t); } else if (is_positive == T_FALSE) { ca_uinf(res, ctx); } else { ca_unknown(res, ctx); } } else if (is_integer == T_FALSE) { ca_t y; fmpz_t t, u; slong n; ca_init(y, ctx); fmpz_init(t); fmpz_init(u); ca_set_d(y, 0.5, ctx); ca_sub(y, x, y, ctx); if (ca_get_fmpz(t, y, ctx) && fmpz_cmp_si(t, expand_limit) < 0 && fmpz_cmp_si(t, -expand_limit) > 0) { n = fmpz_get_si(t); ca_pi(res, ctx); ca_sqrt(res, res, ctx); if (n != 0) { if (n >= 0) { fmpz_fac_ui(t, 2 * n); fmpz_fac_ui(u, n); fmpz_mul_2exp(u, u, 2 * n); } else { fmpz_fac_ui(t, -n); fmpz_mul_2exp(t, t, -2 * n); fmpz_fac_ui(u, -2 * n); if (n & 1) fmpz_neg(t, t); } ca_mul_fmpz(res, res, t, ctx); ca_div_fmpz(res, res, u, ctx); } } else { _ca_gamma_verbatim(res, x, ctx); } ca_clear(y, ctx); fmpz_clear(t); fmpz_clear(u); } else { is_positive = ca_re_is_positive(x, ctx); if (is_positive == T_TRUE) { _ca_gamma_verbatim(res, x, ctx); } else { ca_unknown(res, ctx); } } } } calcium-0.4.1/ca/get_acb.c000066400000000000000000000053551407704557200152670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "arb_fmpz_poly.h" #include "ca.h" void ca_get_acb(acb_t res, const ca_t x, slong prec, ca_ctx_t ctx) { slong wp, initial, maxprec, exact_check_prec; acb_indeterminate(res); initial = prec * 1.05 + 30; maxprec = FLINT_MAX(2 * initial, ctx->options[CA_OPT_PREC_LIMIT]); exact_check_prec = FLINT_MIN(maxprec, initial * 16); for (wp = initial; wp <= maxprec; wp *= 2) { ca_get_acb_raw(res, x, wp, ctx); if (acb_rel_accuracy_bits(res) >= prec) break; if (wp == exact_check_prec) { if (ca_check_is_zero(x, ctx) == T_TRUE) { acb_zero(res); break; } } } } void ca_get_acb_accurate_parts(acb_t res, const ca_t x, slong prec, ca_ctx_t ctx) { slong wp, initial, maxprec, exact_check_prec; int re_ok, im_ok; acb_indeterminate(res); initial = prec * 1.05 + 30; maxprec = FLINT_MAX(2 * initial, ctx->options[CA_OPT_PREC_LIMIT]); exact_check_prec = FLINT_MIN(maxprec, initial * 16); for (wp = initial; wp <= maxprec; wp *= 2) { ca_get_acb_raw(res, x, wp, ctx); re_ok = arb_rel_accuracy_bits(acb_realref(res)) >= prec; im_ok = arb_rel_accuracy_bits(acb_imagref(res)) >= prec; if (re_ok && im_ok) break; if (wp == exact_check_prec) { if (acb_rel_accuracy_bits(res) < prec && ca_check_is_zero(x, ctx) == T_TRUE) { acb_zero(res); break; } if (re_ok && ca_check_is_real(x, ctx) == T_TRUE) { arb_zero(acb_imagref(res)); break; } if (im_ok && ca_check_is_imaginary(x, ctx) == T_TRUE) { arb_zero(acb_realref(res)); break; } } } } char * ca_get_decimal_str(const ca_t x, slong digits, ulong flags, ca_ctx_t ctx) { calcium_stream_t t; acb_t v; digits = FLINT_MAX(digits, 1); acb_init(v); calcium_stream_init_str(t); if (flags & 1) ca_get_acb_accurate_parts(v, x, digits * 3.333 + 1, ctx); else ca_get_acb(v, x, digits * 3.333 + 1, ctx); if (acb_is_finite(v)) calcium_write_acb(t, v, digits, ARB_STR_NO_RADIUS); else calcium_write(t, "?"); acb_clear(v); return t->s; } calcium-0.4.1/ca/get_acb_raw.c000066400000000000000000000050221407704557200161270ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "arb_fmpz_poly.h" #include "ca.h" #include "ca_ext.h" void ca_get_acb_raw(acb_t res, const ca_t x, slong prec, ca_ctx_t ctx) { ca_field_srcptr xfield; if (CA_IS_SPECIAL(x)) { acb_indeterminate(res); return; } if (CA_IS_QQ(x, ctx)) { acb_set_fmpq(res, CA_FMPQ(x), prec); return; } if (CA_IS_QQ_I(x, ctx)) { const fmpz *n, *d; n = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); d = QNF_ELEM_DENREF(CA_NF_ELEM(x)); if (fmpz_is_one(d)) { arb_set_round_fmpz(acb_realref(res), n, prec); arb_set_round_fmpz(acb_imagref(res), n + 1, prec); } else { arb_fmpz_div_fmpz(acb_realref(res), n, d, prec); arb_fmpz_div_fmpz(acb_imagref(res), n + 1, d, prec); } return; } xfield = CA_FIELD(x, ctx); if (CA_FIELD_IS_NF(xfield)) { if (CA_FIELD_NF(xfield)->flag & NF_LINEAR) flint_abort(); ca_ext_get_acb_raw(res, CA_FIELD_EXT_ELEM(xfield, 0), prec, ctx); if (CA_FIELD_NF(xfield)->flag & NF_QUADRATIC) { _arb_fmpz_poly_evaluate_acb(res, QNF_ELEM_NUMREF(CA_NF_ELEM(x)), 2, res, prec); acb_div_fmpz(res, res, QNF_ELEM_DENREF(CA_NF_ELEM(x)), prec); } else { _arb_fmpz_poly_evaluate_acb(res, NF_ELEM_NUMREF(CA_NF_ELEM(x)), NF_ELEM(CA_NF_ELEM(x))->length, res, prec); acb_div_fmpz(res, res, NF_ELEM_DENREF(CA_NF_ELEM(x)), prec); } } else { acb_ptr v; slong i, n; n = CA_FIELD_LENGTH(xfield); if (n == 1) { ca_ext_get_acb_raw(res, CA_FIELD_EXT_ELEM(xfield, 0), prec, ctx); fmpz_mpoly_q_evaluate_acb(res, CA_MPOLY_Q(x), res, prec, CA_FIELD_MCTX(xfield, ctx)); } else { v = _acb_vec_init(n); for (i = 0; i < n; i++) ca_ext_get_acb_raw(v + i, CA_FIELD_EXT_ELEM(xfield, i), prec, ctx); fmpz_mpoly_q_evaluate_acb(res, CA_MPOLY_Q(x), v, prec, CA_FIELD_MCTX(xfield, ctx)); _acb_vec_clear(v, n); } } } calcium-0.4.1/ca/get_fexpr.c000066400000000000000000000253361407704557200156670ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "fexpr.h" #include "fexpr_builtin.h" void _fexpr_set_fmpz_poly_decreasing(fexpr_t res, const fmpz * coeffs, slong len, const fexpr_t var) { slong i, j, num_terms; fexpr_ptr terms; fexpr_t t, u; if (len == 1) { fexpr_set_fmpz(res, coeffs); return; } num_terms = 0; for (i = 0; i < len; i++) num_terms += !fmpz_is_zero(coeffs + i); if (num_terms == 0) { fexpr_zero(res); return; } fexpr_init(t); fexpr_init(u); terms = _fexpr_vec_init(num_terms); j = 0; for (i = len - 1; i >= 0; i--) { if (!fmpz_is_zero(coeffs + i)) { if (i == 0) { fexpr_set_fmpz(terms + j, coeffs + i); } else { if (i == 1) { fexpr_set(u, var); } else { fexpr_set_ui(t, i); fexpr_pow(u, var, t); } if (fmpz_is_one(coeffs + i)) { fexpr_set(terms + j, u); } else { fexpr_set_fmpz(t, coeffs + i); fexpr_mul(terms + j, t, u); } } j++; } } if (num_terms == 1) { fexpr_swap(res, terms); } else { fexpr_set_symbol_builtin(t, FEXPR_Add); fexpr_call_vec(res, t, terms, num_terms); } _fexpr_vec_clear(terms, num_terms); fexpr_clear(t); fexpr_clear(u); } void fexpr_set_nf_elem(fexpr_t res, const nf_elem_t a, const nf_t nf, const fexpr_t var) { const fmpz * num; const fmpz * den; slong len; if (nf_elem_is_zero(a, nf)) { fexpr_zero(res); return; } if (nf->flag & NF_LINEAR) { den = LNF_ELEM_DENREF(a); num = LNF_ELEM_NUMREF(a); len = 1 - fmpz_is_zero(num); } else if (nf->flag & NF_QUADRATIC) { den = QNF_ELEM_DENREF(a); num = QNF_ELEM_NUMREF(a); len = 3; while (len != 0 && fmpz_is_zero(num + len - 1)) len--; } else { den = NF_ELEM(a)->den; num = NF_ELEM(a)->coeffs; len = NF_ELEM(a)->length; } if (fmpz_is_one(den)) { _fexpr_set_fmpz_poly_decreasing(res, num, len, var); } else { fexpr_t p, q; fexpr_init(p); fexpr_init(q); _fexpr_set_fmpz_poly_decreasing(p, num, len, var); fexpr_set_fmpz(q, den); fexpr_div(res, p, q); fexpr_clear(p); fexpr_clear(q); } } void ca_all_extensions(ca_ext_ptr ** extensions, slong * len, const ca_t x, ca_ctx_t ctx); void _ca_get_fexpr_given_ext(fexpr_t res, const ca_t x, ulong flags, ca_ext_ptr * ext, slong num_ext, const fexpr_struct * ext_vars, ca_ctx_t ctx) { ca_field_ptr K; ca_ext_ptr X; slong i, ext_pos; if (CA_IS_QQ(x, ctx)) { fexpr_set_fmpq(res, CA_FMPQ(x)); return; } if (CA_IS_UNKNOWN(x)) { fexpr_set_symbol_builtin(res, FEXPR_Unknown); return; } if (CA_IS_UNDEFINED(x)) { fexpr_set_symbol_builtin(res, FEXPR_Undefined); return; } if (CA_IS_UNSIGNED_INF(x)) { fexpr_set_symbol_builtin(res, FEXPR_UnsignedInfinity); return; } if (CA_IS_SIGNED_INF(x)) { ca_t t; fexpr_t s; ca_init(t, ctx); ca_sgn(t, x, ctx); if (CA_IS_QQ(t, ctx)) { fexpr_set_symbol_builtin(res, FEXPR_Infinity); if (!fmpq_is_one(CA_FMPQ(t))) fexpr_neg(res, res); } else { fexpr_init(s); _ca_get_fexpr_given_ext(s, t, flags, ext, num_ext, ext_vars, ctx); fexpr_set_symbol_builtin(res, FEXPR_Infinity); fexpr_call_builtin2(res, FEXPR_Mul, s, res); fexpr_clear(s); } ca_clear(t, ctx); return; } if (CA_IS_SPECIAL(x)) { flint_printf("_ca_get_fexpr_given_ext: unexpected special value\n"); flint_abort(); } K = CA_FIELD(x, ctx); if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { X = CA_FIELD_EXT_ELEM(K, 0); ext_pos = -1; for (i = 0; i < num_ext; i++) { if (ext[i] == X) { ext_pos = i; break; } } if (ext_pos == -1) { flint_printf("Unable to look up ext position\n"); flint_abort(); } fexpr_set_nf_elem(res, CA_NF_ELEM(x), CA_FIELD_NF(K), ext_vars + ext_pos); return; } else { fexpr_vec_t xvars; slong i, j, nvars; nvars = CA_FIELD_LENGTH(K); xvars->entries = flint_malloc(sizeof(fexpr_struct) * nvars); xvars->length = xvars->alloc = nvars; j = 0; for (i = 0; i < nvars; i++) { for ( ; j < num_ext; j++) { if (ext[j] == CA_FIELD_EXT_ELEM(K, i)) { xvars->entries[i] = ext_vars[j]; break; } } if (j == num_ext) { flint_printf("_ca_get_fexpr_given_ext: ext not found!\n"); flint_abort(); } } fexpr_set_fmpz_mpoly_q(res, CA_MPOLY_Q(x), xvars, CA_FIELD_MCTX(K, ctx)); flint_free(xvars->entries); return; } fexpr_set_symbol_builtin(res, FEXPR_Unknown); } #define GET_UNARY(fsymbol) \ _ca_get_fexpr_given_ext(res, CA_EXT_FUNC_ARGS(x), flags, ext, num_ext, ext_vars, ctx); \ fexpr_call_builtin1(res, fsymbol, res); \ return; \ void _ca_ext_get_fexpr_given_ext(fexpr_t res, const ca_ext_t x, ulong flags, ca_ext_ptr * ext, slong num_ext, const fexpr_struct * ext_vars, ca_ctx_t ctx) { if (CA_EXT_IS_QQBAR(x)) { if (flags & CA_FEXPR_SERIALIZATION) qqbar_get_fexpr_repr(res, CA_EXT_QQBAR(x)); else if (!qqbar_get_fexpr_formula(res, CA_EXT_QQBAR(x), QQBAR_FORMULA_GAUSSIANS | QQBAR_FORMULA_QUADRATICS)) qqbar_get_fexpr_root_nearest(res, CA_EXT_QQBAR(x)); } else { slong f, nargs; fexpr_t t, u; f = CA_EXT_HEAD(x); nargs = CA_EXT_FUNC_NARGS(x); nargs = nargs; /* Todo: make a table */ switch (f) { case CA_Pi: fexpr_set_symbol_builtin(res, FEXPR_Pi); return; case CA_Euler: fexpr_set_symbol_builtin(res, FEXPR_Euler); return; case CA_Exp: GET_UNARY(FEXPR_Exp) case CA_Log: GET_UNARY(FEXPR_Log) case CA_Sin: GET_UNARY(FEXPR_Sin) case CA_Cos: GET_UNARY(FEXPR_Cos) case CA_Tan: GET_UNARY(FEXPR_Tan) case CA_Cot: GET_UNARY(FEXPR_Cot) case CA_Atan: GET_UNARY(FEXPR_Atan) case CA_Asin: GET_UNARY(FEXPR_Asin) case CA_Acos: GET_UNARY(FEXPR_Acos) case CA_Sign: GET_UNARY(FEXPR_Sign) case CA_Abs: GET_UNARY(FEXPR_Abs) case CA_Sqrt: GET_UNARY(FEXPR_Sqrt) case CA_Re: GET_UNARY(FEXPR_Re) case CA_Im: GET_UNARY(FEXPR_Im) case CA_Conjugate: GET_UNARY(FEXPR_Conjugate) case CA_Floor: GET_UNARY(FEXPR_Floor) case CA_Ceil: GET_UNARY(FEXPR_Ceil) case CA_Gamma: GET_UNARY(FEXPR_Gamma) case CA_Erf: GET_UNARY(FEXPR_Erf) case CA_Erfc: GET_UNARY(FEXPR_Erfc) case CA_Erfi: GET_UNARY(FEXPR_Erfi) case CA_Pow: fexpr_init(t); fexpr_init(u); _ca_get_fexpr_given_ext(t, CA_EXT_FUNC_ARGS(x), flags, ext, num_ext, ext_vars, ctx); _ca_get_fexpr_given_ext(u, CA_EXT_FUNC_ARGS(x) + 1, flags, ext, num_ext, ext_vars, ctx); fexpr_call_builtin2(res, FEXPR_Pow, t, u); fexpr_clear(t); fexpr_clear(u); return; } fexpr_set_symbol_builtin(res, FEXPR_Unknown); } } void _ca_default_variables(fexpr_ptr ext_vars, slong num_ext) { slong i; if (num_ext <= 26 && 0) { char tmp[20]; for (i = 0; i < num_ext; i++) { tmp[0] = 'a' + i; tmp[1] = '\0'; fexpr_set_symbol_str(ext_vars + i, tmp); } } else { char tmp[20]; for (i = 0; i < num_ext; i++) { flint_sprintf(tmp, "a_%wd", i + 1); fexpr_set_symbol_str(ext_vars + i, tmp); } } } void ca_get_fexpr(fexpr_t res, const ca_t x, ulong flags, ca_ctx_t ctx) { ca_ext_ptr * ext; slong i, num_ext; fexpr_struct * ext_vars; fexpr_struct * where_args; fexpr_t t; if (CA_IS_QQ(x, ctx)) { fexpr_set_fmpq(res, CA_FMPQ(x)); return; } if (CA_IS_UNKNOWN(x)) { fexpr_set_symbol_builtin(res, FEXPR_Unknown); return; } if (CA_IS_UNDEFINED(x)) { fexpr_set_symbol_builtin(res, FEXPR_Undefined); return; } if (CA_IS_UNSIGNED_INF(x)) { fexpr_set_symbol_builtin(res, FEXPR_UnsignedInfinity); return; } if (CA_IS_SIGNED_INF(x)) { ca_t t; ca_init(t, ctx); ca_sgn(t, x, ctx); if (CA_IS_QQ(t, ctx)) { fexpr_set_symbol_builtin(res, FEXPR_Infinity); if (!fmpq_is_one(CA_FMPQ(t))) fexpr_neg(res, res); ca_clear(t, ctx); return; } ca_clear(t, ctx); } ca_all_extensions(&ext, &num_ext, x, ctx); ext_vars = _fexpr_vec_init(num_ext); where_args = _fexpr_vec_init(num_ext + 1); fexpr_init(t); _ca_default_variables(ext_vars, num_ext); _ca_get_fexpr_given_ext(where_args + 0, x, flags, ext, num_ext, ext_vars, ctx); for (i = 0; i < num_ext; i++) { _ca_ext_get_fexpr_given_ext(t, ext[i], flags, ext, num_ext, ext_vars, ctx); fexpr_call_builtin2(where_args + i + 1, FEXPR_Def, ext_vars + i, t); } fexpr_set_symbol_builtin(t, FEXPR_Where); fexpr_call_vec(res, t, where_args, num_ext + 1); flint_free(ext); fexpr_clear(t); _fexpr_vec_clear(ext_vars, num_ext); _fexpr_vec_clear(where_args, num_ext + 1); } calcium-0.4.1/ca/get_qqbar.c000066400000000000000000000325751407704557200156540ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" int ca_get_qqbar(qqbar_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { return 0; } else if (CA_IS_QQ(x, ctx)) { qqbar_set_fmpq(res, CA_FMPQ(x)); return 1; } else { if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { const fmpz * num; const fmpz * den; slong len; if (CA_FIELD_NF(CA_FIELD(x, ctx))->flag & NF_LINEAR) { num = (fmpz *) LNF_ELEM_NUMREF(CA_NF_ELEM(x)); den = LNF_ELEM_DENREF(CA_NF_ELEM(x)); len = 1; } else if (CA_FIELD_NF(CA_FIELD(x, ctx))->flag & NF_QUADRATIC) { num = (fmpz *) QNF_ELEM_NUMREF(CA_NF_ELEM(x)); den = QNF_ELEM_DENREF(CA_NF_ELEM(x)); len = 2; } else { num = (fmpz *) NF_ELEM_NUMREF(CA_NF_ELEM(x)); den = NF_ELEM_DENREF(CA_NF_ELEM(x)); len = NF_ELEM(CA_NF_ELEM(x))->length; } _qqbar_evaluate_fmpq_poly(res, num, den, len, CA_FIELD_NF_QQBAR(CA_FIELD(x, ctx))); return 1; } else { slong i, len, deg_limit, bits_limit; qqbar_ptr xs; qqbar_t y, zero; int success; int * init_mask, * used; if (!ca_can_evaluate_qqbar(x, ctx)) return 0; deg_limit = ctx->options[CA_OPT_QQBAR_DEG_LIMIT]; bits_limit = 10 * ctx->options[CA_OPT_PREC_LIMIT]; /* xxx */ len = CA_FIELD_LENGTH(CA_FIELD(x, ctx)); success = 0; xs = (qqbar_struct *) flint_malloc(sizeof(qqbar_struct) * len); init_mask = (int *) flint_calloc(sizeof(int), len); used = (int *) flint_calloc(sizeof(int), len); qqbar_init(y); qqbar_init(zero); fmpz_mpoly_q_used_vars(used, CA_MPOLY_Q(x), CA_FIELD_MCTX(CA_FIELD(x, ctx), ctx)); /* todo: allow non-qqbar extension elements to cache a qqbar value */ for (i = 0; i < len; i++) { if (!used[i]) { xs[i] = *zero; continue; } if (CA_EXT_IS_QQBAR(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i))) { xs[i] = *CA_EXT_QQBAR(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)); } else if (CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)->data.func_data.qqbar != NULL) { xs[i] = *(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)->data.func_data.qqbar); } else if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)) == CA_Sqrt) { qqbar_init(xs + i); init_mask[i] = 1; if (!ca_get_qqbar(xs + i, CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)), ctx)) goto cleanup; /* todo: maybe do a x2 bounds check */ qqbar_sqrt(xs + i, xs + i); /* todo: avoid copy here... */ CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)->data.func_data.qqbar = flint_malloc(sizeof(qqbar_struct)); qqbar_init(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)->data.func_data.qqbar); qqbar_set(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)->data.func_data.qqbar, xs + i); } else if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)) == CA_Abs) { qqbar_init(xs + i); init_mask[i] = 1; if (!ca_get_qqbar(xs + i, CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)), ctx)) goto cleanup; /* todo: bounds check */ qqbar_abs(xs + i, xs + i); } else if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)) == CA_Sign) { qqbar_init(xs + i); init_mask[i] = 1; if (!ca_get_qqbar(xs + i, CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)), ctx)) goto cleanup; /* todo: bounds check */ qqbar_sgn(xs + i, xs + i); } else if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)) == CA_Re) { qqbar_init(xs + i); init_mask[i] = 1; if (!ca_get_qqbar(xs + i, CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)), ctx)) goto cleanup; /* todo: bounds check */ qqbar_re(xs + i, xs + i); } else if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)) == CA_Im) { qqbar_init(xs + i); init_mask[i] = 1; if (!ca_get_qqbar(xs + i, CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)), ctx)) goto cleanup; /* todo: bounds check */ qqbar_im(xs + i, xs + i); } else if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)) == CA_Conjugate) { qqbar_init(xs + i); init_mask[i] = 1; if (!ca_get_qqbar(xs + i, CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)), ctx)) goto cleanup; qqbar_conj(xs + i, xs + i); } else if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)) == CA_Floor) { qqbar_init(xs + i); init_mask[i] = 1; if (!ca_get_qqbar(xs + i, CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)), ctx)) goto cleanup; { fmpz_t t; fmpz_init(t); qqbar_floor(t, xs + i); qqbar_set_fmpz(xs + i, t); fmpz_clear(t); } } else if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)) == CA_Ceil) { qqbar_init(xs + i); init_mask[i] = 1; if (!ca_get_qqbar(xs + i, CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)), ctx)) goto cleanup; { fmpz_t t; fmpz_init(t); qqbar_ceil(t, xs + i); qqbar_set_fmpz(xs + i, t); fmpz_clear(t); } } else if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)) == CA_Pow) { ca_srcptr base, exp; qqbar_init(xs + i); init_mask[i] = 1; base = CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)); exp = CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), i)) + 1; if (!CA_IS_QQ(exp, ctx)) goto cleanup; if (!ca_get_qqbar(xs + i, base, ctx)) goto cleanup; /* todo: better condition on the exponent numerator */ if (fmpz_bits(fmpq_denref(CA_FMPQ(exp))) > 20 || fmpz_bits(fmpq_numref(CA_FMPQ(exp))) > 20 || *fmpq_denref(CA_FMPQ(exp)) * qqbar_degree(xs + i) > ctx->options[CA_OPT_QQBAR_DEG_LIMIT] || (qqbar_height_bits(xs + i) + 1) * fmpz_bits(fmpq_numref(CA_FMPQ(exp))) > ctx->options[CA_OPT_PREC_LIMIT]) goto cleanup; qqbar_root_ui(xs + i, xs + i, *fmpq_denref(CA_FMPQ(exp))); if (*fmpq_numref(CA_FMPQ(exp)) >= 0) { qqbar_pow_ui(xs + i, xs + i, *fmpq_numref(CA_FMPQ(exp))); } else { qqbar_inv(xs + i, xs + i); qqbar_pow_ui(xs + i, xs + i, -*fmpq_numref(CA_FMPQ(exp))); } } } if (qqbar_evaluate_fmpz_mpoly(y, fmpz_mpoly_q_numref(CA_MPOLY_Q(x)), xs, deg_limit, bits_limit, CA_FIELD_MCTX(CA_FIELD(x, ctx), ctx))) { if (qqbar_evaluate_fmpz_mpoly(res, fmpz_mpoly_q_denref(CA_MPOLY_Q(x)), xs, deg_limit, bits_limit, CA_FIELD_MCTX(CA_FIELD(x, ctx), ctx))) { if (qqbar_binop_within_limits(y, res, deg_limit, bits_limit)) { qqbar_div(res, y, res); success = 1; } } } cleanup: for (i = 0; i < len; i++) { if (init_mask[i]) qqbar_clear(xs + i); } flint_free(init_mask); flint_free(used); flint_free(xs); qqbar_clear(y); qqbar_clear(zero); return success; } } } int ca_get_fmpq(fmpq_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { return 0; } else if (CA_IS_QQ(x, ctx)) { fmpq_set(res, CA_FMPQ(x)); return 1; } else if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { if (nf_elem_is_rational(CA_NF_ELEM(x), CA_FIELD_NF(CA_FIELD(x, ctx)))) { const fmpz * num; const fmpz * den; slong len; if (CA_FIELD_NF(CA_FIELD(x, ctx))->flag & NF_LINEAR) { num = (fmpz *) LNF_ELEM_NUMREF(CA_NF_ELEM(x)); den = LNF_ELEM_DENREF(CA_NF_ELEM(x)); fmpz_set(fmpq_numref(res), num); fmpz_set(fmpq_denref(res), den); } else if (CA_FIELD_NF(CA_FIELD(x, ctx))->flag & NF_QUADRATIC) { num = (fmpz *) QNF_ELEM_NUMREF(CA_NF_ELEM(x)); den = QNF_ELEM_DENREF(CA_NF_ELEM(x)); fmpz_set(fmpq_numref(res), num); fmpz_set(fmpq_denref(res), den); } else { num = (fmpz *) NF_ELEM_NUMREF(CA_NF_ELEM(x)); den = NF_ELEM_DENREF(CA_NF_ELEM(x)); len = NF_ELEM(CA_NF_ELEM(x))->length; if (len == 0) { fmpq_zero(res); } else { fmpz_set(fmpq_numref(res), num); fmpz_set(fmpq_denref(res), den); } } return 1; } else { return 0; } } else { /* todo: exclude complex numbers, obviously irrational numbers before evaluating */ int success; qqbar_t t; qqbar_init(t); success = ca_get_qqbar(t, x, ctx); if (success && qqbar_is_rational(t)) { qqbar_get_fmpq(res, t); success = 1; } else { success = 0; } qqbar_clear(t); return success; } } int ca_get_fmpz(fmpz_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { return 0; } else if (CA_IS_QQ(x, ctx)) { if (fmpz_is_one(fmpq_denref(CA_FMPQ(x)))) { fmpz_set(res, fmpq_numref(CA_FMPQ(x))); return 1; } return 0; } else if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { if (nf_elem_is_integer(CA_NF_ELEM(x), CA_FIELD_NF(CA_FIELD(x, ctx)))) { const fmpz * num; slong len; if (CA_FIELD_NF(CA_FIELD(x, ctx))->flag & NF_LINEAR) { num = (fmpz *) LNF_ELEM_NUMREF(CA_NF_ELEM(x)); fmpz_set(res, num); } else if (CA_FIELD_NF(CA_FIELD(x, ctx))->flag & NF_QUADRATIC) { num = (fmpz *) QNF_ELEM_NUMREF(CA_NF_ELEM(x)); fmpz_set(res, num); } else { num = (fmpz *) NF_ELEM_NUMREF(CA_NF_ELEM(x)); len = NF_ELEM(CA_NF_ELEM(x))->length; if (len == 0) fmpz_zero(res); else fmpz_set(res, num); } return 1; } else { return 0; } } else { /* todo: exclude (numerically) obvious non-integers before evaluating */ int success; qqbar_t t; qqbar_init(t); success = ca_get_qqbar(t, x, ctx); if (success && qqbar_is_integer(t)) { qqbar_get_fmpz(res, t); success = 1; } else { success = 0; } qqbar_clear(t); return success; } } calcium-0.4.1/ca/hash_repr.c000066400000000000000000000044471407704557200156570ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" ulong ca_hash_repr(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { return 123; /* not really interesting ... */ } else if (CA_IS_QQ(x, ctx)) { ulong a, b; a = calcium_fmpz_hash(CA_FMPQ_NUMREF(x)); b = calcium_fmpz_hash(CA_FMPQ_DENREF(x)); return a + 781237663 * b; } else if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { const fmpz * num; const fmpz * den; slong i, len; ulong hash; if (CA_FIELD_NF(CA_FIELD(x, ctx))->flag & NF_LINEAR) { num = (fmpz *) LNF_ELEM_NUMREF(CA_NF_ELEM(x)); den = LNF_ELEM_DENREF(CA_NF_ELEM(x)); len = 1; } else if (CA_FIELD_NF(CA_FIELD(x, ctx))->flag & NF_QUADRATIC) { num = (fmpz *) QNF_ELEM_NUMREF(CA_NF_ELEM(x)); den = QNF_ELEM_DENREF(CA_NF_ELEM(x)); len = 2; } else { num = (fmpz *) NF_ELEM_NUMREF(CA_NF_ELEM(x)); den = NF_ELEM_DENREF(CA_NF_ELEM(x)); len = NF_ELEM(CA_NF_ELEM(x))->length; } hash = CA_EXT_HASH(CA_FIELD_EXT_ELEM(CA_FIELD(x, ctx), 0)); hash = 1000003 * calcium_fmpz_hash(den) + hash; for (i = 0; i < len; i++) hash = calcium_fmpz_hash(num + i) * 1000003 + hash; return hash; } else { slong i; ulong hash; const fmpz_mpoly_struct *p, *q; hash = CA_FIELD_HASH(CA_FIELD(x, ctx)); p = fmpz_mpoly_q_numref(CA_MPOLY_Q(x)); q = fmpz_mpoly_q_numref(CA_MPOLY_Q(x)); /* fixme: this only looks at coefficients -- accessing exponents is annoying */ for (i = 0; i < p->length; i++) hash = calcium_fmpz_hash(p->coeffs + i) * 1000003 + hash; for (i = 0; i < q->length; i++) hash = calcium_fmpz_hash(q->coeffs + i) * 1000003 + hash; return hash; } } calcium-0.4.1/ca/i.c000066400000000000000000000010541407704557200141230ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_i(ca_t x, ca_ctx_t ctx) { _ca_make_field_element(x, ctx->field_qq_i, ctx); nf_elem_gen(CA_NF_ELEM(x), CA_FIELD_NF(ctx->field_qq_i)); } calcium-0.4.1/ca/im.c000066400000000000000000000027211407704557200143020ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_im(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (CA_IS_UNKNOWN(x)) ca_unknown(res, ctx); else ca_undefined(res, ctx); } else if (CA_IS_QQ(x, ctx)) { ca_zero(res, ctx); } else if (CA_IS_QQ_I(x, ctx)) { const fmpz *n, *d; fmpq_t t; n = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); d = QNF_ELEM_DENREF(CA_NF_ELEM(x)); fmpq_init(t); fmpq_set_fmpz_frac(t, n + 1, d); ca_set_fmpq(res, t, ctx); fmpq_clear(t); } else if (ca_check_is_real(x, ctx) == T_TRUE) /* todo: avoid duplicate computations with is_real/is_imaginary */ { ca_zero(res, ctx); } else if (ca_check_is_imaginary(x, ctx) == T_TRUE) { ca_t t; ca_init(t, ctx); ca_neg_i(t, ctx); ca_mul(res, x, t, ctx); ca_clear(t, ctx); } else { _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Im, x), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } } calcium-0.4.1/ca/init.c000066400000000000000000000010331407704557200146330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_init(ca_t x, ca_ctx_t ctx) { x->field = (ulong) ctx->field_qq; *CA_FMPQ_NUMREF(x) = 0; *CA_FMPQ_DENREF(x) = 1; } calcium-0.4.1/ca/inlines.c000066400000000000000000000006521407704557200153370ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #define CA_INLINES_C #include "ca.h" calcium-0.4.1/ca/inv.c000066400000000000000000000052101407704557200144650ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_inv(ca_t res, const ca_t x, ca_ctx_t ctx) { truth_t is_zero; ca_field_srcptr field; if (CA_IS_QQ(x, ctx)) { if (fmpq_is_zero(CA_FMPQ(x))) { ca_uinf(res, ctx); } else { _ca_make_fmpq(res, ctx); fmpq_inv(CA_FMPQ(res), CA_FMPQ(x)); } return; } if (CA_IS_SPECIAL(x)) { if (CA_IS_INF(x)) ca_zero(res, ctx); else ca_set(res, x, ctx); return; } is_zero = ca_check_is_zero(x, ctx); if (is_zero == T_TRUE) { ca_uinf(res, ctx); return; } else if (is_zero == T_UNKNOWN) { ca_unknown(res, ctx); return; } field = CA_FIELD(x, ctx); _ca_make_field_element(res, field, ctx); if (CA_FIELD_IS_QQ(field)) /* todo: should not happen? */ { fmpq_inv(CA_FMPQ(res), CA_FMPQ(x)); } else if (CA_FIELD_IS_NF(field)) { nf_elem_inv(CA_NF_ELEM(res), CA_NF_ELEM(x), CA_FIELD_NF(field)); } else { fmpz_mpoly_q_inv(CA_MPOLY_Q(res), CA_MPOLY_Q(x), CA_FIELD_MCTX(field, ctx)); _ca_mpoly_q_simplify_fraction_ideal(CA_MPOLY_Q(res), field, ctx); } } void ca_inv_no_division_by_zero(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_field_srcptr field; if (ca_is_zero_check_fast(x, ctx) == T_TRUE) { flint_printf("ca_inv_no_division_by_zero: zero element encountered!\n"); flint_abort(); } if (CA_IS_QQ(x, ctx)) { _ca_make_fmpq(res, ctx); fmpq_inv(CA_FMPQ(res), CA_FMPQ(x)); return; } if (CA_IS_SPECIAL(x)) { if (CA_IS_INF(x)) ca_zero(res, ctx); else ca_set(res, x, ctx); return; } field = CA_FIELD(x, ctx); _ca_make_field_element(res, field, ctx); if (CA_FIELD_IS_QQ(field)) /* todo: should not happen? */ { fmpq_inv(CA_FMPQ(res), CA_FMPQ(x)); } else if (CA_FIELD_IS_NF(field)) { nf_elem_inv(CA_NF_ELEM(res), CA_NF_ELEM(x), CA_FIELD_NF(field)); } else { fmpz_mpoly_q_inv(CA_MPOLY_Q(res), CA_MPOLY_Q(x), CA_FIELD_MCTX(field, ctx)); _ca_mpoly_q_simplify_fraction_ideal(CA_MPOLY_Q(res), field, ctx); } } calcium-0.4.1/ca/is_cyclotomic_nf_elem.c000066400000000000000000000014711407704557200202230ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int ca_is_cyclotomic_nf_elem(slong * p, ulong * q, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) return 0; if (CA_IS_QQ(x, ctx)) return 0; if (CA_IS_QQ_I(x, ctx)) { if (p != NULL) p[0] = 1; if (q != NULL) q[0] = 4; return 1; } return CA_FIELD_IS_NF(CA_FIELD(x, ctx)) && qqbar_is_root_of_unity(p, q, CA_FIELD_NF_QQBAR(CA_FIELD(x, ctx))); } calcium-0.4.1/ca/is_gen_as_ext.c000066400000000000000000000022741407704557200165070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" ca_ext_ptr ca_is_gen_as_ext(const ca_t x, ca_ctx_t ctx) { ca_field_ptr K; if (CA_IS_SPECIAL(x)) return NULL; K = CA_FIELD(x, ctx); if (CA_FIELD_IS_QQ(K)) return NULL; if (CA_FIELD_IS_NF(K)) { if (!nf_elem_is_gen(CA_NF_ELEM(x), CA_FIELD_NF(K))) return NULL; return CA_FIELD_EXT_ELEM(K, 0); } if (fmpz_mpoly_is_one(fmpz_mpoly_q_denref(CA_MPOLY_Q(x)), CA_FIELD_MCTX(K, ctx))) { if (fmpz_mpoly_is_gen(fmpz_mpoly_q_numref(CA_MPOLY_Q(x)), -1, CA_FIELD_MCTX(K, ctx))) { slong i; for (i = 0; ; i++) if (fmpz_mpoly_is_gen(fmpz_mpoly_q_numref(CA_MPOLY_Q(x)), i, CA_FIELD_MCTX(K, ctx))) return CA_FIELD_EXT_ELEM(K, i); } } return NULL; } calcium-0.4.1/ca/log.c000066400000000000000000000204211407704557200144530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" ca_ext_ptr ca_is_gen_pow_fmpz_as_ext(fmpz_t exp, const ca_t x, ca_ctx_t ctx) { ca_field_ptr K; if (CA_IS_SPECIAL(x)) return NULL; K = CA_FIELD(x, ctx); if (CA_FIELD_IS_QQ(K)) return NULL; /* todo: detect powers of the generator in number fields */ if (CA_FIELD_IS_NF(K)) { if (!nf_elem_is_gen(CA_NF_ELEM(x), CA_FIELD_NF(K))) return NULL; fmpz_one(exp); return CA_FIELD_EXT_ELEM(K, 0); } if (fmpz_mpoly_is_one(fmpz_mpoly_q_denref(CA_MPOLY_Q(x)), CA_FIELD_MCTX(K, ctx))) { if (fmpz_mpoly_length(fmpz_mpoly_q_numref(CA_MPOLY_Q(x)), CA_FIELD_MCTX(K, ctx)) == 1 && fmpz_is_one(fmpz_mpoly_q_numref(CA_MPOLY_Q(x))->coeffs)) { int * used; slong i, which, num_used; used = flint_calloc(CA_FIELD_LENGTH(K), sizeof(int)); fmpz_mpoly_q_used_vars_num(used, CA_MPOLY_Q(x), CA_FIELD_MCTX(K, ctx)); which = num_used = 0; for (i = 0; i < CA_FIELD_LENGTH(K); i++) { if (used[i]) { which = i; num_used++; } } flint_free(used); if (num_used == 1) { fmpz_mpoly_total_degree_fmpz(exp, fmpz_mpoly_q_numref(CA_MPOLY_Q(x)), CA_FIELD_MCTX(K, ctx)); return CA_FIELD_EXT_ELEM(K, which); } } } if (fmpz_mpoly_is_one(fmpz_mpoly_q_numref(CA_MPOLY_Q(x)), CA_FIELD_MCTX(K, ctx))) { if (fmpz_mpoly_length(fmpz_mpoly_q_denref(CA_MPOLY_Q(x)), CA_FIELD_MCTX(K, ctx)) == 1 && fmpz_is_one(fmpz_mpoly_q_denref(CA_MPOLY_Q(x))->coeffs)) { int * used; slong i, which, num_used; used = flint_calloc(CA_FIELD_LENGTH(K), sizeof(int)); fmpz_mpoly_q_used_vars_den(used, CA_MPOLY_Q(x), CA_FIELD_MCTX(K, ctx)); which = num_used = 0; for (i = 0; i < CA_FIELD_LENGTH(K); i++) { if (used[i]) { which = i; num_used++; } } flint_free(used); if (num_used == 1) { fmpz_mpoly_total_degree_fmpz(exp, fmpz_mpoly_q_denref(CA_MPOLY_Q(x)), CA_FIELD_MCTX(K, ctx)); fmpz_neg(exp, exp); return CA_FIELD_EXT_ELEM(K, which); } } } return NULL; } /* log(exp(z)) -- http://fungrim.org/entry/a3a253/ */ void ca_log_exp(ca_t res, const ca_t z, ca_ctx_t ctx) { ca_t t, pi; if (CA_IS_SPECIAL(z)) flint_abort(); ca_init(t, ctx); ca_init(pi, ctx); ca_pi(pi, ctx); ca_im(t, z, ctx); ca_div(t, t, pi, ctx); ca_sub_ui(t, t, 1, ctx); ca_div_ui(t, t, 2, ctx); ca_ceil(t, t, ctx); if (ca_check_is_zero(t, ctx) == T_TRUE) { ca_set(res, z, ctx); } else { ca_t pi_i; ca_init(pi_i, ctx); ca_pi_i(pi_i, ctx); ca_mul(t, t, pi_i, ctx); ca_mul_ui(t, t, 2, ctx); ca_sub(res, z, t, ctx); ca_clear(pi_i, ctx); } ca_clear(t, ctx); ca_clear(pi, ctx); } /* log(z^a), assuming z != 0 */ void ca_log_pow(ca_t res, const ca_t z, const ca_t a, ca_ctx_t ctx) { ca_t t, u, pi; if (CA_IS_SPECIAL(z) || CA_IS_SPECIAL(a)) flint_abort(); ca_init(t, ctx); ca_init(u, ctx); ca_init(pi, ctx); ca_log(u, z, ctx); ca_mul(u, u, a, ctx); ca_pi(pi, ctx); ca_im(t, u, ctx); ca_div(t, t, pi, ctx); ca_sub_ui(t, t, 1, ctx); ca_div_ui(t, t, 2, ctx); ca_ceil(t, t, ctx); if (ca_check_is_zero(t, ctx) == T_TRUE) { ca_set(res, u, ctx); } else { ca_t pi_i; ca_init(pi_i, ctx); ca_pi_i(pi_i, ctx); ca_mul(t, t, pi_i, ctx); ca_mul_ui(t, t, 2, ctx); ca_sub(res, u, t, ctx); ca_clear(pi_i, ctx); } ca_clear(t, ctx); ca_clear(u, ctx); ca_clear(pi, ctx); } void ca_log(ca_t res, const ca_t x, ca_ctx_t ctx) { truth_t is_zero; ca_ext_ptr ext; if (CA_IS_SPECIAL(x)) { if (ca_check_is_infinity(x, ctx) == T_TRUE) ca_pos_inf(res, ctx); else if (ca_check_is_undefined(x, ctx) == T_TRUE) ca_undefined(res, ctx); else ca_unknown(res, ctx); return; } is_zero = ca_check_is_zero(x, ctx); if (is_zero == T_TRUE) { ca_neg_inf(res, ctx); return; } if (is_zero == T_UNKNOWN) { ca_unknown(res, ctx); return; } if (ca_check_is_one(x, ctx) == T_TRUE) { ca_zero(res, ctx); return; } /* log(i) and log(-i) */ if (CA_IS_QQ_I(x, ctx)) { if (ca_check_is_i(x, ctx) == T_TRUE) { ca_pi_i(res, ctx); ca_div_si(res, res, 2, ctx); return; } else if (ca_check_is_neg_i(x, ctx) == T_TRUE) { ca_pi_i(res, ctx); ca_div_si(res, res, -2, ctx); return; } } ext = ca_is_gen_as_ext(x, ctx); /* Fast detection of roots of unity. Todo: also detect roots of unity when in a number field, and in other situations. */ if (ext != NULL && CA_EXT_HEAD(ext) == CA_QQBar) { slong p; ulong q; if (qqbar_log_pi_i(&p, &q, CA_EXT_QQBAR(ext))) { ca_pi_i(res, ctx); ca_mul_si(res, res, p, ctx); ca_div_ui(res, res, q, ctx); return; } } if (ext != NULL && CA_EXT_HEAD(ext) == CA_Exp) { /* log(exp(z)) */ ca_log_exp(res, CA_EXT_FUNC_ARGS(ext), ctx); return; } if (ca_check_is_negative_real(x, ctx) == T_TRUE) { ca_t pi_i; ca_init(pi_i, ctx); ca_pi_i(pi_i, ctx); ca_neg(res, x, ctx); ca_log(res, res, ctx); ca_add(res, res, pi_i, ctx); ca_clear(pi_i, ctx); return; } if (ext != NULL && CA_EXT_HEAD(ext) == CA_Pow) { /* log(z^a) */ if (ca_check_is_zero(CA_EXT_FUNC_ARGS(ext), ctx) == T_FALSE) { ca_log_pow(res, CA_EXT_FUNC_ARGS(ext), CA_EXT_FUNC_ARGS(ext) + 1, ctx); return; } } if (ext != NULL && CA_EXT_HEAD(ext) == CA_Sqrt) { /* log(sqrt(z)) */ ca_t h; ca_init(h, ctx); ca_one(h, ctx); ca_div_ui(h, h, 2, ctx); ca_log_pow(res, CA_EXT_FUNC_ARGS(ext), h, ctx); ca_clear(h, ctx); return; } /* If x is not a generator, maybe it is a power of a generator */ { fmpz_t n; ca_t t; int success = 0; fmpz_init(n); ca_init(t, ctx); ext = ca_is_gen_pow_fmpz_as_ext(n, x, ctx); if (ext != NULL && CA_EXT_HEAD(ext) == CA_Exp) { /* log(exp(z)^n) = log(exp(n*z)) */ ca_mul_fmpz(t, CA_EXT_FUNC_ARGS(ext), n, ctx); ca_log_exp(res, t, ctx); success = 1; } if (ext != NULL && CA_EXT_HEAD(ext) == CA_Pow) { /* log((z^a)^n) = log(z^(a*n)) */ if (ca_check_is_zero(CA_EXT_FUNC_ARGS(ext), ctx) == T_FALSE) { ca_mul_fmpz(t, CA_EXT_FUNC_ARGS(ext) + 1, n, ctx); ca_log_pow(res, CA_EXT_FUNC_ARGS(ext), t, ctx); success = 1; } } if (ext != NULL && CA_EXT_HEAD(ext) == CA_Sqrt) { /* log(sqrt(z)^n) = log(z^(n/2)) */ ca_set_fmpz(t, n, ctx); ca_div_ui(t, t, 2, ctx); ca_log_pow(res, CA_EXT_FUNC_ARGS(ext), t, ctx); success = 1; } fmpz_clear(n); ca_clear(t, ctx); if (success) return; } _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Log, x), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } calcium-0.4.1/ca/make_field_element.c000066400000000000000000000025511407704557200174670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_field.h" void ca_clear_unchecked(ca_t x, ca_ctx_t ctx); /* todo: recycle storage when compatible */ void _ca_make_field_element(ca_t x, ca_field_srcptr field, ca_ctx_t ctx) { ca_field_srcptr old_field; if (field == NULL) { flint_printf("NULL in _ca_make_field_element\n"); flint_abort(); } old_field = (ca_field_srcptr) (x->field & ~CA_SPECIAL); if (old_field == field) { x->field = (ulong) field; /* unset special status */ return; } ca_clear_unchecked(x, ctx); if (field == ctx->field_qq) { *CA_FMPQ_NUMREF(x) = 0; *CA_FMPQ_DENREF(x) = 1; } else if (CA_FIELD_IS_NF(field)) { nf_elem_init(CA_NF_ELEM(x), CA_FIELD_NF(field)); } else { x->elem.mpoly_q = (fmpz_mpoly_q_struct *) flint_malloc(sizeof(fmpz_mpoly_q_struct)); fmpz_mpoly_q_init(CA_MPOLY_Q(x), CA_FIELD_MCTX(field, ctx)); } x->field = (ulong) field; } calcium-0.4.1/ca/merge_fields.c000066400000000000000000000165171407704557200163320ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" #include "utils_flint.h" void _nf_elem_get_fmpz_poly_den_shallow(fmpz_poly_t pol, fmpz_t den, const nf_elem_t a, const nf_t nf) { if (nf->flag & NF_LINEAR) { pol->coeffs = (fmpz *) LNF_ELEM_NUMREF(a); *den = *LNF_ELEM_DENREF(a); pol->length = 1; if (fmpz_is_zero(pol->coeffs)) pol->length--; } else if (nf->flag & NF_QUADRATIC) { pol->coeffs = (fmpz *) QNF_ELEM_NUMREF(a); *den = *QNF_ELEM_DENREF(a); pol->length = 2; if (fmpz_is_zero(pol->coeffs + 1)) { pol->length--; if (fmpz_is_zero(pol->coeffs)) pol->length--; } } else { pol->coeffs = (fmpz *) NF_ELEM_NUMREF(a); pol->length = NF_ELEM(a)->length; *den = *NF_ELEM_DENREF(a); } pol->alloc = pol->length; } void ca_merge_fields(ca_t resx, ca_t resy, const ca_t x, const ca_t y, ca_ctx_t ctx) { ca_field_srcptr xfield, yfield, field; ca_ext_struct ** ext; slong *xgen_map, *ygen_map; slong xlen, ylen, ext_len; slong ext_alloc; slong ix, iy; int cmp; if (CA_IS_SPECIAL(x) || CA_IS_SPECIAL(y)) { flint_printf("ca_merge_fields: inputs must be field elements, not special values\n"); flint_abort(); } xfield = CA_FIELD(x, ctx); yfield = CA_FIELD(y, ctx); if (xfield == yfield || CA_FIELD_IS_QQ(xfield) || CA_FIELD_IS_QQ(yfield)) { ca_set(resx, x, ctx); ca_set(resy, y, ctx); return; } if (x == resx || y == resy) { flint_printf("ca_merge_fields: aliasing not implemented!\n"); flint_abort(); } xlen = CA_FIELD_LENGTH(xfield); ylen = CA_FIELD_LENGTH(yfield); ext_alloc = xlen + ylen; ext = flint_malloc(ext_alloc * sizeof(ca_ext_struct *)); ext_len = 0; xgen_map = flint_malloc(xlen * sizeof(slong)); ygen_map = flint_malloc(ylen * sizeof(slong)); /* printf("merge fields of len %ld and len %ld\n", xlen, ylen); for (ix = 0; ix < xlen; ix++) { printf("x: "); ca_ext_print(CA_FIELD_EXT_ELEM(xfield, ix), ctx); printf("\n"); } for (iy = 0; iy < ylen; iy++) { printf("y: "); ca_ext_print(CA_FIELD_EXT_ELEM(yfield, iy), ctx); printf("\n"); } */ /* merge field lists */ ix = iy = 0; while (ix < xlen || iy < ylen) { if (ix < xlen && iy < ylen) { cmp = ca_ext_cmp_repr(CA_FIELD_EXT_ELEM(xfield, ix), CA_FIELD_EXT_ELEM(yfield, iy), ctx); cmp = -cmp; /* more complex first, for elimination order */ if (cmp == 0) { if (CA_FIELD_EXT_ELEM(xfield, ix) != CA_FIELD_EXT_ELEM(yfield, iy)) flint_abort(); ext[ext_len] = CA_FIELD_EXT_ELEM(xfield, ix); xgen_map[ix] = ext_len; ygen_map[iy] = ext_len; ix++; iy++; } else if (cmp < 0) { ext[ext_len] = CA_FIELD_EXT_ELEM(xfield, ix); xgen_map[ix] = ext_len; ix++; } else { ext[ext_len] = CA_FIELD_EXT_ELEM(yfield, iy); ygen_map[iy] = ext_len; iy++; } ext_len++; } else if (ix < xlen) { ext[ext_len] = CA_FIELD_EXT_ELEM(xfield, ix); xgen_map[ix] = ext_len; ix++; ext_len++; } else { ext[ext_len] = CA_FIELD_EXT_ELEM(yfield, iy); ygen_map[iy] = ext_len; iy++; ext_len++; } } /* printf("merged length %ld\n", ext_len); */ field = ca_field_cache_insert_ext(CA_CTX_FIELD_CACHE(ctx), ext, ext_len, ctx); /* printf("MERGE FIELDS:\n"); if (CA_FIELD_LENGTH(xfield) > 100) flint_abort(); ca_field_print(xfield, ctx); printf("\n"); if (CA_FIELD_LENGTH(yfield) > 100) flint_abort(); ca_field_print(yfield, ctx); printf("\n"); if (CA_FIELD_LENGTH(field) > 100) flint_abort(); ca_field_print(field, ctx); printf("\n\n"); */ if (xfield == field) { ca_set(resx, x, ctx); } else { /* todo: allow aliasing */ _ca_make_field_element(resx, field, ctx); if (CA_FIELD_IS_NF(xfield)) { fmpz_poly_t pol; fmpz_t den; _nf_elem_get_fmpz_poly_den_shallow(pol, den, CA_NF_ELEM(x), CA_FIELD_NF(xfield)); fmpz_mpoly_set_gen_fmpz_poly(fmpz_mpoly_q_numref(CA_MPOLY_Q(resx)), xgen_map[0], pol, CA_FIELD_MCTX(field, ctx)); fmpz_mpoly_set_fmpz(fmpz_mpoly_q_denref(CA_MPOLY_Q(resx)), den, CA_FIELD_MCTX(field, ctx)); } else { fmpz_mpoly_compose_fmpz_mpoly_gen(fmpz_mpoly_q_numref(CA_MPOLY_Q(resx)), fmpz_mpoly_q_numref(CA_MPOLY_Q(x)), xgen_map, CA_FIELD_MCTX(xfield, ctx), CA_FIELD_MCTX(field, ctx)); fmpz_mpoly_compose_fmpz_mpoly_gen(fmpz_mpoly_q_denref(CA_MPOLY_Q(resx)), fmpz_mpoly_q_denref(CA_MPOLY_Q(x)), xgen_map, CA_FIELD_MCTX(xfield, ctx), CA_FIELD_MCTX(field, ctx)); } } if (yfield == field) { ca_set(resy, y, ctx); } else { /* todo: allow aliasing */ _ca_make_field_element(resy, field, ctx); if (CA_FIELD_IS_NF(yfield)) { fmpz_poly_t pol; fmpz_t den; _nf_elem_get_fmpz_poly_den_shallow(pol, den, CA_NF_ELEM(y), CA_FIELD_NF(yfield)); fmpz_mpoly_set_gen_fmpz_poly(fmpz_mpoly_q_numref(CA_MPOLY_Q(resy)), ygen_map[0], pol, CA_FIELD_MCTX(field, ctx)); fmpz_mpoly_set_fmpz(fmpz_mpoly_q_denref(CA_MPOLY_Q(resy)), den, CA_FIELD_MCTX(field, ctx)); } else { fmpz_mpoly_compose_fmpz_mpoly_gen(fmpz_mpoly_q_numref(CA_MPOLY_Q(resy)), fmpz_mpoly_q_numref(CA_MPOLY_Q(y)), ygen_map, CA_FIELD_MCTX(yfield, ctx), CA_FIELD_MCTX(field, ctx)); fmpz_mpoly_compose_fmpz_mpoly_gen(fmpz_mpoly_q_denref(CA_MPOLY_Q(resy)), fmpz_mpoly_q_denref(CA_MPOLY_Q(y)), ygen_map, CA_FIELD_MCTX(yfield, ctx), CA_FIELD_MCTX(field, ctx)); } } flint_free(ext); flint_free(xgen_map); flint_free(ygen_map); } calcium-0.4.1/ca/mul.c000066400000000000000000000140361407704557200144740ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_mul_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx) { ca_field_srcptr field; if (CA_IS_SPECIAL(x)) { if (CA_IS_SIGNED_INF(x)) { if (fmpq_is_zero(y)) ca_undefined(res, ctx); else if (fmpq_sgn(y) > 0) ca_set(res, x, ctx); else ca_neg(res, x, ctx); } else if (CA_IS_UNSIGNED_INF(x)) { if (fmpq_is_zero(y)) ca_undefined(res, ctx); else ca_set(res, x, ctx); } else { ca_set(res, x, ctx); } return; } if (fmpq_is_zero(y)) { ca_zero(res, ctx); return; } if (CA_IS_QQ(x, ctx)) { _ca_make_fmpq(res, ctx); fmpq_mul(CA_FMPQ(res), CA_FMPQ(x), y); } else { field = CA_FIELD(x, ctx); _ca_make_field_element(res, field, ctx); if (CA_FIELD_IS_NF(field)) { nf_elem_scalar_mul_fmpq(CA_NF_ELEM(res), CA_NF_ELEM(x), y, CA_FIELD_NF(field)); } else { fmpz_mpoly_q_mul_fmpq(CA_MPOLY_Q(res), CA_MPOLY_Q(x), y, CA_FIELD_MCTX(field, ctx)); } } } void ca_mul_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx) { fmpq_t t; *fmpq_numref(t) = *y; *fmpq_denref(t) = 1; ca_mul_fmpq(res, x, t, ctx); } void ca_mul_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx) { fmpz_t t; fmpz_init_set_ui(t, y); ca_mul_fmpz(res, x, t, ctx); fmpz_clear(t); } void ca_mul_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx) { fmpz_t t; fmpz_init_set_si(t, y); ca_mul_fmpz(res, x, t, ctx); fmpz_clear(t); } void ca_mul(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) { ca_field_srcptr xfield, yfield, zfield; xfield = CA_FIELD(x, ctx); yfield = CA_FIELD(y, ctx); if (CA_IS_QQ(x, ctx) && (xfield == yfield)) { _ca_make_fmpq(res, ctx); fmpq_mul(CA_FMPQ(res), CA_FMPQ(x), CA_FMPQ(y)); return; } if (CA_IS_QQ(y, ctx)) { if (res == y) { fmpq_t t; fmpq_init(t); fmpq_set(t, CA_FMPQ(y)); ca_mul_fmpq(res, x, t, ctx); fmpq_clear(t); } else { ca_mul_fmpq(res, x, CA_FMPQ(y), ctx); } return; } if (CA_IS_QQ(x, ctx)) { if (res == x) { fmpq_t t; fmpq_init(t); fmpq_set(t, CA_FMPQ(x)); ca_mul_fmpq(res, y, t, ctx); fmpq_clear(t); } else { ca_mul_fmpq(res, y, CA_FMPQ(x), ctx); } return; } if (CA_IS_SPECIAL(x) || CA_IS_SPECIAL(y)) { if (CA_IS_UNDEFINED(x) || CA_IS_UNDEFINED(y)) { ca_undefined(res, ctx); return; } if (CA_IS_UNKNOWN(x) || CA_IS_UNKNOWN(y)) { ca_unknown(res, ctx); return; } if (CA_IS_UNSIGNED_INF(x) && CA_IS_INF(y)) { ca_uinf(res, ctx); return; } if (CA_IS_UNSIGNED_INF(y) && CA_IS_INF(x)) { ca_uinf(res, ctx); return; } if (CA_IS_UNSIGNED_INF(x) && !CA_IS_SPECIAL(y)) { truth_t zero = ca_check_is_zero(y, ctx); if (zero == T_TRUE) ca_undefined(res, ctx); else if (zero == T_FALSE) ca_uinf(res, ctx); else ca_unknown(res, ctx); return; } if (CA_IS_UNSIGNED_INF(y) && !CA_IS_SPECIAL(x)) { truth_t zero = ca_check_is_zero(x, ctx); if (zero == T_TRUE) ca_undefined(res, ctx); else if (zero == T_FALSE) ca_uinf(res, ctx); else ca_unknown(res, ctx); return; } if (CA_IS_SIGNED_INF(x) || CA_IS_SIGNED_INF(y)) { ca_t t, u; truth_t xzero, yzero; xzero = ca_check_is_zero(x, ctx); yzero = ca_check_is_zero(y, ctx); if (xzero == T_TRUE || yzero == T_TRUE) { ca_undefined(res, ctx); return; } if (xzero == T_UNKNOWN || yzero == T_UNKNOWN) { ca_unknown(res, ctx); return; } ca_init(t, ctx); ca_init(u, ctx); ca_sgn(t, x, ctx); ca_sgn(u, y, ctx); ca_mul(res, t, u, ctx); if (ca_check_is_number(res, ctx) == T_TRUE) res->field |= CA_INF; ca_clear(t, ctx); ca_clear(u, ctx); return; } ca_unknown(res, ctx); return; } if (xfield == yfield) { zfield = xfield; _ca_make_field_element(res, zfield, ctx); if (CA_FIELD_IS_NF(zfield)) { nf_elem_mul(CA_NF_ELEM(res), CA_NF_ELEM(x), CA_NF_ELEM(y), CA_FIELD_NF(zfield)); } else { fmpz_mpoly_q_mul(CA_MPOLY_Q(res), CA_MPOLY_Q(x), CA_MPOLY_Q(y), CA_FIELD_MCTX(zfield, ctx)); _ca_mpoly_q_reduce_ideal(CA_MPOLY_Q(res), zfield, ctx); _ca_mpoly_q_simplify_fraction_ideal(CA_MPOLY_Q(res), zfield, ctx); } ca_condense_field(res, ctx); return; } { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); ca_merge_fields(t, u, x, y, ctx); ca_mul(res, t, u, ctx); ca_condense_field(res, ctx); ca_clear(t, ctx); ca_clear(u, ctx); } } calcium-0.4.1/ca/neg.c000066400000000000000000000025011407704557200144420ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_neg(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_field_srcptr field; ulong field_flags; if (CA_IS_QQ(x, ctx)) { _ca_make_fmpq(res, ctx); fmpq_neg(CA_FMPQ(res), CA_FMPQ(x)); return; } if (CA_IS_SPECIAL(x)) { if (CA_IS_UNKNOWN(x) || CA_IS_UNDEFINED(x) || CA_IS_UNSIGNED_INF(x)) { ca_set(res, x, ctx); return; } } field_flags = x->field; _ca_make_field_element(res, (ca_field_ptr) (field_flags & ~CA_SPECIAL), ctx); field = CA_FIELD(res, ctx); res->field = field_flags; /* set special flags */ if (field == ctx->field_qq) { fmpq_neg(CA_FMPQ(res), CA_FMPQ(x)); } else if (CA_FIELD_IS_NF(field)) { nf_elem_neg(CA_NF_ELEM(res), CA_NF_ELEM(x), CA_FIELD_NF(field)); } else { fmpz_mpoly_q_neg(CA_MPOLY_Q(res), CA_MPOLY_Q(x), CA_FIELD_MCTX(field, ctx)); } } calcium-0.4.1/ca/neg_i.c000066400000000000000000000007471407704557200147640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_neg_i(ca_t x, ca_ctx_t ctx) { ca_i(x, ctx); ca_neg(x, x, ctx); } calcium-0.4.1/ca/neg_i_inf.c000066400000000000000000000007601407704557200156130ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_neg_i_inf(ca_t x, ca_ctx_t ctx) { ca_neg_i(x, ctx); x->field |= CA_INF; } calcium-0.4.1/ca/neg_inf.c000066400000000000000000000007631407704557200153060ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_neg_inf(ca_t x, ca_ctx_t ctx) { ca_set_si(x, -1, ctx); x->field |= CA_INF; } calcium-0.4.1/ca/neg_one.c000066400000000000000000000010601407704557200153020ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_neg_one(ca_t x, ca_ctx_t ctx) { _ca_make_fmpq(x, ctx); fmpz_one(fmpq_denref(CA_FMPQ(x))); fmpz_set_si(fmpq_numref(CA_FMPQ(x)), -1); } calcium-0.4.1/ca/one.c000066400000000000000000000007611407704557200144600ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_one(ca_t x, ca_ctx_t ctx) { _ca_make_fmpq(x, ctx); fmpq_one(CA_FMPQ(x)); } calcium-0.4.1/ca/pi.c000066400000000000000000000011021407704557200142750ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_pi(ca_t res, ca_ctx_t ctx) { _ca_make_field_element(res, _ca_ctx_get_field_const(ctx, CA_Pi), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } calcium-0.4.1/ca/pi_i.c000066400000000000000000000010731407704557200146140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_pi_i(ca_t res, ca_ctx_t ctx) { ca_t t; ca_init(t, ctx); ca_pi(res, ctx); ca_i(t, ctx); ca_mul(res, res, t, ctx); ca_clear(t, ctx); } calcium-0.4.1/ca/pos_i_inf.c000066400000000000000000000007531407704557200156450ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_pos_i_inf(ca_t x, ca_ctx_t ctx) { ca_i(x, ctx); x->field |= CA_INF; } calcium-0.4.1/ca/pos_inf.c000066400000000000000000000007541407704557200153360ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_pos_inf(ca_t x, ca_ctx_t ctx) { ca_one(x, ctx); x->field |= CA_INF; } calcium-0.4.1/ca/pow.c000066400000000000000000000271751407704557200145140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" slong nf_elem_bits(const nf_elem_t x, nf_t nf) { slong b, c; if (nf->flag & NF_LINEAR) { flint_abort(); } else if (nf->flag & NF_QUADRATIC) { b = fmpz_bits(QNF_ELEM_NUMREF(x)); c = fmpz_bits(QNF_ELEM_NUMREF(x) + 1); b = FLINT_MAX(b, c); c = fmpz_bits(QNF_ELEM_DENREF(x)); b = FLINT_MAX(b, c); return b; } else { b = _fmpz_vec_max_bits(NF_ELEM_NUMREF(x), NF_ELEM(x)->length); b = FLINT_ABS(b); c = fmpz_bits(NF_ELEM_DENREF(x)); b = FLINT_MAX(b, c); return b; } } void _ca_pow_binexp(ca_t res, const ca_t x, slong n, ca_ctx_t ctx) { if (n == 0) { ca_one(res, ctx); } else if (n == 1) { ca_set(res, x, ctx); } else if (n == 2) { ca_mul(res, x, x, ctx); } else if (n < 0) { ca_inv(res, x, ctx); _ca_pow_binexp(res, res, -n, ctx); } else { /* todo: is left-to-right or right-to-left better? */ if (n % 2 == 0) { #if 0 _ca_pow_binexp(res, x, n / 2, ctx); _ca_pow_binexp(res, res, 2, ctx); #else _ca_pow_binexp(res, x, 2, ctx); _ca_pow_binexp(res, res, n / 2, ctx); #endif } else { if (res == x) { ca_t t; ca_init(t, ctx); _ca_pow_binexp(t, x, n - 1, ctx); ca_mul(res, t, x, ctx); ca_clear(t, ctx); } else { _ca_pow_binexp(res, x, n - 1, ctx); ca_mul(res, res, x, ctx); } } } } void ca_pow_si_arithmetic(ca_t res, const ca_t x, slong n, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { ca_unknown(res, ctx); } else if (n == 0) { ca_one(res, ctx); } else if (n == 1) { ca_set(res, x, ctx); } else if (n == -1) { ca_inv(res, x, ctx); } else if (n == 2) { ca_sqr(res, x, ctx); } else if (CA_IS_QQ(x, ctx)) { if (n < 0 && fmpq_is_zero(CA_FMPQ(x))) { ca_uinf(res, ctx); } else { fmpq_t t; fmpq_init(t); fmpq_pow_si(t, CA_FMPQ(x), n); ca_set_fmpq(res, t, ctx); fmpq_clear(t); } } else if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { ca_t t; /* Need to be sure we don't divide by zero, but more generally the base should never be a rational number here. */ if (nf_elem_is_rational(CA_NF_ELEM(x), CA_FIELD_NF(CA_FIELD(x, ctx)))) { flint_printf("ca_pow_fmpz: unexpected rational nf_elem\n"); flint_abort(); } ca_init(t, ctx); if (n >= 0) ca_set(t, x, ctx); else { ca_inv(t, x, ctx); n = -n; } nf_elem_pow(CA_NF_ELEM(t), CA_NF_ELEM(t), n, CA_FIELD_NF(CA_FIELD(t, ctx))); ca_condense_field(t, ctx); ca_swap(res, t, ctx); ca_clear(t, ctx); } else { _ca_pow_binexp(res, x, n, ctx); } } /* (z^a)^b, assuming z != 0 */ void ca_pow_pow(ca_t res, const ca_t z, const ca_t a, const ca_t b, ca_ctx_t ctx) { ca_t t, u, pi; if (CA_IS_SPECIAL(z) || CA_IS_SPECIAL(a) || CA_IS_SPECIAL(b)) flint_abort(); ca_init(t, ctx); ca_init(u, ctx); ca_init(pi, ctx); ca_log(u, z, ctx); ca_mul(u, u, a, ctx); ca_pi(pi, ctx); ca_im(t, u, ctx); ca_div(t, t, pi, ctx); ca_sub_ui(t, t, 1, ctx); ca_div_ui(t, t, 2, ctx); ca_ceil(t, t, ctx); if (ca_check_is_zero(t, ctx) == T_TRUE) { ca_mul(u, a, b, ctx); ca_pow(res, z, u, ctx); } else { ca_t pi_i; ca_init(pi_i, ctx); ca_pi_i(pi_i, ctx); ca_mul(t, t, pi_i, ctx); ca_mul_ui(t, t, 2, ctx); ca_mul(t, t, b, ctx); ca_neg(t, t, ctx); ca_exp(t, t, ctx); ca_mul(u, a, b, ctx); ca_pow(res, z, u, ctx); ca_mul(res, res, t, ctx); ca_clear(pi_i, ctx); } ca_clear(t, ctx); ca_clear(u, ctx); ca_clear(pi, ctx); } /* warning: must have already checked for special values */ void _ca_pow_inert(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) { _ca_function_fxy(res, CA_Pow, x, y, ctx); _ca_mpoly_q_reduce_ideal(CA_MPOLY_Q(res), CA_FIELD(res, ctx), ctx); ca_condense_field(res, ctx); } void _ca_pow_general(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x) || CA_IS_SPECIAL(y)) { ca_unknown(res, ctx); return; } { ca_ext_ptr ext = ca_is_gen_as_ext(x, ctx); /* (z^a)^b */ /* todo: also detect ((z^a)^n)^b, etc. */ if (ext != NULL && CA_EXT_HEAD(ext) == CA_Pow) { if (ca_check_is_zero(CA_EXT_FUNC_ARGS(ext), ctx) == T_FALSE) { ca_pow_pow(res, CA_EXT_FUNC_ARGS(ext), CA_EXT_FUNC_ARGS(ext) + 1, y, ctx); return; } } } /* todo: more simplifications */ /* inert pow must be a number -- avoid division by zero */ /* todo: more generally handle re(y) > 0 */ if (!(CA_IS_QQ(y, ctx) && fmpz_sgn(CA_FMPQ_NUMREF(y)) > 0)) { if (ca_check_is_zero(x, ctx) != T_FALSE) { /* todo: implement various cases */ ca_unknown(res, ctx); return; } } _ca_pow_inert(res, x, y, ctx); } void ca_pow_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (CA_IS_UNSIGNED_INF(x)) { if (fmpz_sgn(y) > 0) ca_uinf(res, ctx); else if (fmpz_sgn(y) < 0) ca_zero(res, ctx); else ca_undefined(res, ctx); } else if (CA_IS_SIGNED_INF(x)) { if (fmpz_is_zero(y)) ca_undefined(res, ctx); else if (fmpz_sgn(y) < 0) ca_zero(res, ctx); else { ca_t t; ca_init(t, ctx); ca_sgn(t, x, ctx); ca_pow_fmpz(t, t, y, ctx); ca_pos_inf(res, ctx); ca_mul(res, res, t, ctx); ca_clear(t, ctx); } } else { /* unknown, undefined map to themselves */ ca_set(res, x, ctx); } return; } /* Deal with the most common cases */ if (fmpz_is_zero(y)) { ca_one(res, ctx); return; } if (fmpz_is_one(y)) { ca_set(res, x, ctx); return; } if (fmpz_equal_si(y, -1)) { ca_inv(res, x, ctx); return; } if (fmpz_equal_si(y, 2)) { ca_mul(res, x, x, ctx); return; } if (fmpz_equal_si(y, -2)) { ca_inv(res, x, ctx); ca_mul(res, res, res, ctx); return; } /* Rational base */ if (CA_IS_QQ(x, ctx)) { /* 0^y, y != 0 */ if (fmpz_is_zero(CA_FMPQ_NUMREF(x))) { if (fmpz_sgn(y) < 0) ca_uinf(res, ctx); else ca_zero(res, ctx); return; } /* 1^y or (-1)^y */ if (fmpz_is_one(CA_FMPQ_DENREF(x)) && fmpz_is_pm1(CA_FMPQ_NUMREF(x))) { if (fmpz_is_one(CA_FMPQ_NUMREF(x)) || fmpz_is_even(y)) ca_one(res, ctx); else ca_neg_one(res, ctx); return; } if (fmpz_bits(y) <= FLINT_BITS - 2) { slong xbits1, xbits2; xbits1 = fmpz_bits(CA_FMPQ_NUMREF(x)); xbits2 = fmpz_bits(CA_FMPQ_DENREF(x)); xbits1 = FLINT_MAX(xbits1, xbits2); if (xbits1 * (double) FLINT_ABS(*y) < ctx->options[CA_OPT_PREC_LIMIT]) { fmpq_t t; fmpq_init(t); fmpq_pow_si(t, CA_FMPQ(x), *y); ca_set_fmpq(res, t, ctx); fmpq_clear(t); return; } } } /* Todo: special case all roots of unity */ /* Number field base */ if (CA_FIELD_IS_NF(CA_FIELD(x, ctx)) && fmpz_bits(y) <= FLINT_BITS - 2) { slong xbits1; xbits1 = nf_elem_bits(CA_NF_ELEM(x), CA_FIELD_NF(CA_FIELD(x, ctx))); /* Need to be sure we don't divide by zero, but more generally the base should never be a rational number here. */ if (nf_elem_is_rational(CA_NF_ELEM(x), CA_FIELD_NF(CA_FIELD(x, ctx)))) { flint_printf("ca_pow_fmpz: unexpected rational nf_elem\n"); flint_abort(); } if (xbits1 * (double) FLINT_ABS(*y) < ctx->options[CA_OPT_PREC_LIMIT]) { ca_t t; ca_init(t, ctx); if (fmpz_sgn(y) > 0) ca_set(t, x, ctx); else ca_inv(t, x, ctx); nf_elem_pow(CA_NF_ELEM(t), CA_NF_ELEM(t), FLINT_ABS(*y), CA_FIELD_NF(CA_FIELD(t, ctx))); ca_condense_field(t, ctx); ca_swap(res, t, ctx); ca_clear(t, ctx); return; } } /* todo: evaluation limits */ if (fmpz_cmp_si(y, -ctx->options[CA_OPT_POW_LIMIT]) >= 0 && fmpz_cmp_si(y, ctx->options[CA_OPT_POW_LIMIT]) <= 0) { _ca_pow_binexp(res, x, *y, ctx); return; } { ca_t t; ca_init(t, ctx); ca_set_fmpz(t, y, ctx); _ca_pow_general(res, x, t, ctx); ca_clear(t, ctx); } } void ca_pow(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) { if (CA_IS_QQ(y, ctx) && fmpz_is_one(CA_FMPQ_DENREF(y))) { ca_pow_fmpz(res, x, CA_FMPQ_NUMREF(y), ctx); return; } if (CA_IS_SPECIAL(x) || CA_IS_SPECIAL(y)) { ca_unknown(res, ctx); return; } if (CA_IS_QQ(y, ctx) && fmpz_equal_ui(CA_FMPQ_DENREF(y), 2)) { if (fmpz_equal_si(CA_FMPQ_NUMREF(y), 1)) { ca_sqrt(res, x, ctx); return; } else if (fmpz_equal_si(CA_FMPQ_NUMREF(y), 3)) { ca_t t; ca_init(t, ctx); ca_sqrt(t, x, ctx); ca_mul(res, t, x, ctx); ca_clear(t, ctx); return; } /* todo: evaluation limits */ else if (fmpz_cmp_si(CA_FMPQ_NUMREF(y), -ctx->options[CA_OPT_POW_LIMIT] / 2) >= 0 && fmpz_cmp_si(CA_FMPQ_NUMREF(y), ctx->options[CA_OPT_POW_LIMIT] / 2) <= 0) { ca_t t; ca_init(t, ctx); ca_sqrt(t, x, ctx); _ca_pow_binexp(res, t, *CA_FMPQ_NUMREF(y), ctx); ca_clear(t, ctx); return; } } _ca_pow_general(res, x, y, ctx); } void ca_pow_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx) { ca_t t; ca_init(t, ctx); ca_set_fmpq(t, y, ctx); ca_pow(res, x, t, ctx); ca_clear(t, ctx); } void ca_pow_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx) { fmpz_t t; fmpz_init(t); fmpz_set_si(t, y); ca_pow_fmpz(res, x, t, ctx); fmpz_clear(t); } void ca_pow_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx) { fmpz_t t; fmpz_init(t); fmpz_set_ui(t, y); ca_pow_fmpz(res, x, t, ctx); fmpz_clear(t); } calcium-0.4.1/ca/print.c000066400000000000000000000350161407704557200150340ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" void calcium_write_fmpz(calcium_stream_t out, const fmpz_t x) { calcium_write_free(out, fmpz_get_str(NULL, 10, x)); } void qqbar_write_n(calcium_stream_t out, const qqbar_t x, slong n) { acb_t t; slong prec; n = FLINT_MAX(1, n); prec = n * 3.333 + 10; acb_init(t); qqbar_get_acb(t, x, prec); calcium_write_acb(out, t, n, ARB_STR_NO_RADIUS); acb_clear(t); } void calcium_write_nf_elem(calcium_stream_t out, const nf_elem_t a, const char * var, const nf_t nf) { const fmpz * num; const fmpz * den; slong len; if (nf_elem_is_zero(a, nf)) { calcium_write(out, "0"); return; } if (nf->flag & NF_LINEAR) { den = LNF_ELEM_DENREF(a); num = LNF_ELEM_NUMREF(a); len = 1 - fmpz_is_zero(num); } else if (nf->flag & NF_QUADRATIC) { den = QNF_ELEM_DENREF(a); num = QNF_ELEM_NUMREF(a); len = 3; while (len != 0 && fmpz_is_zero(num + len - 1)) len--; } else { den = NF_ELEM(a)->den; num = NF_ELEM(a)->coeffs; len = NF_ELEM(a)->length; } if (fmpz_is_one(den)) { calcium_write_free(out, _fmpz_poly_get_str_pretty(num, len, var)); } else { calcium_write(out, "("); calcium_write_free(out, _fmpz_poly_get_str_pretty(num, len, var)); calcium_write(out, ")/"); calcium_write_fmpz(out, den); } } void fmpz_mpoly_q_write_pretty(calcium_stream_t out, const fmpz_mpoly_q_t f, const char ** x, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_one(fmpz_mpoly_q_denref(f), ctx)) { calcium_write_free(out, fmpz_mpoly_get_str_pretty(fmpz_mpoly_q_numref(f), x, ctx)); } else if (fmpz_mpoly_is_fmpz(fmpz_mpoly_q_denref(f), ctx)) { calcium_write(out, "("); calcium_write_free(out, fmpz_mpoly_get_str_pretty(fmpz_mpoly_q_numref(f), x, ctx)); calcium_write(out, ")/"); calcium_write_free(out, fmpz_mpoly_get_str_pretty(fmpz_mpoly_q_denref(f), x, ctx)); } else { calcium_write(out, "("); calcium_write_free(out, fmpz_mpoly_get_str_pretty(fmpz_mpoly_q_numref(f), x, ctx)); calcium_write(out, ")/("); calcium_write_free(out, fmpz_mpoly_get_str_pretty(fmpz_mpoly_q_denref(f), x, ctx)); calcium_write(out, ")"); } } typedef struct { ca_ext_ptr * ext; const char ** ext_vars; slong ext_len; ulong flags; slong digits; int print_where; } ca_print_info_t; void _ca_print(calcium_stream_t out, const ca_t x, ca_print_info_t * info, ca_ctx_t ctx); void _ca_ext_print(calcium_stream_t out, ca_ext_t x, const char * var, ca_print_info_t * info, ca_ctx_t ctx); void _ca_field_print(calcium_stream_t out, const ca_field_t K, ca_print_info_t * info, ca_ctx_t ctx) { slong i, j, len, ideal_len; const char ** field_vars; calcium_write(out, "QQ"); len = CA_FIELD_LENGTH(K); if (len == 0) return; field_vars = flint_malloc(sizeof(char *) * len); for (i = 0; i < len; i++) field_vars[i] = ""; j = 0; for (i = 0; i < len; i++) { for ( ; j < info->ext_len; j++) { if (info->ext[j] == CA_FIELD_EXT_ELEM(K, i)) { field_vars[i] = info->ext_vars[j]; break; } } if (j == info->ext_len) { flint_printf("_ca_field_print: ext not found!\n"); flint_abort(); } } calcium_write(out, "("); for (i = 0; i < len; i++) { calcium_write(out, field_vars[i]); if (i < len - 1) calcium_write(out, ","); } calcium_write(out, ")"); if (CA_FIELD_IS_NF(K)) { calcium_write(out, "/<"); calcium_write_free(out, fmpz_poly_get_str_pretty(QQBAR_POLY(CA_EXT_QQBAR(CA_FIELD_EXT_ELEM(K, 0))), field_vars[0])); calcium_write(out, ">"); } else { ideal_len = CA_FIELD_IDEAL_LENGTH(K); if (ideal_len > 0) { const fmpz_mpoly_ctx_struct * mctx; mctx = CA_FIELD_MCTX(K, ctx); calcium_write(out, "/<"); for (i = 0; i < ideal_len; i++) { calcium_write_free(out, fmpz_mpoly_get_str_pretty(CA_FIELD_IDEAL_ELEM(K, i), (const char **) field_vars, mctx)); if (i < ideal_len - 1) calcium_write(out, ", "); } calcium_write(out, ">"); } } flint_free(field_vars); } void _ca_ext_print(calcium_stream_t out, ca_ext_t x, const char * var, ca_print_info_t * info, ca_ctx_t ctx) { if (x->head == CA_QQBar) { if (info->flags & CA_PRINT_N) { if (qqbar_is_i(CA_EXT_QQBAR(x))) { calcium_write(out, "I"); } else { qqbar_write_n(out, CA_EXT_QQBAR(x), info->digits); } calcium_write(out, " "); } calcium_write(out, "["); calcium_write_free(out, fmpz_poly_get_str_pretty(QQBAR_POLY(CA_EXT_QQBAR(x)), var)); calcium_write(out, "=0]"); } else { acb_t t; if (info->flags & CA_PRINT_N) { acb_init(t); ca_ext_get_acb_raw(t, x, info->digits * 3.33 + 64, ctx); calcium_write_acb(out, t, info->digits, ARB_STR_NO_RADIUS); acb_clear(t); } if (info->flags & CA_PRINT_N) calcium_write(out, " ["); calcium_write(out, calcium_func_name(CA_EXT_HEAD(x))); if (CA_EXT_FUNC_NARGS(x) != 0) { slong i; calcium_write(out, "("); for (i = 0; i < CA_EXT_FUNC_NARGS(x); i++) { _ca_print(out, CA_EXT_FUNC_ARGS(x) + i, info, ctx); if (i < CA_EXT_FUNC_NARGS(x) - 1) calcium_write(out, ", "); } calcium_write(out, ")"); } if (info->flags & CA_PRINT_N) calcium_write(out, "]"); } } void _ca_print(calcium_stream_t out, const ca_t x, ca_print_info_t * info, ca_ctx_t ctx) { ca_field_srcptr xfield; int print_where; if (CA_IS_SPECIAL(x)) { if (CA_IS_UNDEFINED(x)) { calcium_write(out, "Undefined"); } else if (CA_IS_UNKNOWN(x)) { calcium_write(out, "Unknown"); } else if (CA_IS_UNSIGNED_INF(x)) { calcium_write(out, "UnsignedInfinity"); } else if (CA_IS_SIGNED_INF(x)) { ca_t sgn; sgn->field = x->field & ~CA_SPECIAL; sgn->elem = x->elem; if (CA_IS_QQ(sgn, ctx)) { if (fmpq_sgn(CA_FMPQ(sgn)) > 0) calcium_write(out, "+Infinity"); else calcium_write(out, "-Infinity"); } else if (CA_IS_QQ_I(sgn, ctx)) { if (fmpz_sgn(QNF_ELEM_NUMREF(CA_NF_ELEM(sgn)) + 1) > 0) calcium_write(out, "+I * Infinity"); else calcium_write(out, "-I * Infinity"); } else { calcium_write(out, "Infinity * ("); _ca_print(out, sgn, info, ctx); calcium_write(out, ")"); } } return; } print_where = info->print_where; info->print_where = 0; xfield = CA_FIELD(x, ctx); if (CA_FIELD_IS_QQ(xfield) && fmpz_is_one(CA_FMPQ_DENREF(x)) && fmpz_cmp_si(CA_FMPQ_NUMREF(x), -999999) >= 0 && fmpz_cmp_si(CA_FMPQ_NUMREF(x), 999999) <= 0) { calcium_write_free(out, fmpq_get_str(NULL, 10, CA_FMPQ(x))); return; } if (info->flags & CA_PRINT_N) { acb_t t; acb_init(t); ca_get_acb_raw(t, x, info->digits * 3.33 + 64, ctx); calcium_write_acb(out, t, info->digits, ARB_STR_NO_RADIUS); acb_clear(t); } if (info->flags & CA_PRINT_REPR) { if (info->flags & CA_PRINT_N) calcium_write(out, " {"); if (CA_FIELD_IS_QQ(xfield)) { calcium_write_free(out, fmpq_get_str(NULL, 10, CA_FMPQ(x))); } else if (CA_FIELD_IS_NF(xfield)) { slong i; const char * var = NULL; for (i = 0; i < info->ext_len; i++) { if (info->ext[i] == CA_FIELD_EXT_ELEM(xfield, 0)) { var = info->ext_vars[i]; break; } } calcium_write_nf_elem(out, CA_NF_ELEM(x), var, CA_FIELD_NF(xfield)); } else { const char ** field_vars; slong i, j, len; len = CA_FIELD_LENGTH(xfield); field_vars = flint_malloc(sizeof(char *) * len); for (i = 0; i < len; i++) field_vars[i] = ""; j = 0; for (i = 0; i < len; i++) { for ( ; j < info->ext_len; j++) { if (info->ext[j] == CA_FIELD_EXT_ELEM(xfield, i)) { field_vars[i] = info->ext_vars[j]; break; } } if (j == info->ext_len) { flint_printf("_ca_field_print: ext not found!\n"); flint_abort(); } } fmpz_mpoly_q_write_pretty(out, CA_MPOLY_Q(x), (const char **) field_vars, CA_FIELD_MCTX(xfield, ctx)); flint_free(field_vars); } if (info->flags & CA_PRINT_FIELD) { calcium_write(out, " in "); _ca_field_print(out, xfield, info, ctx); } if (print_where && info->ext_len > 0) { slong i, len; len = info->ext_len; calcium_write(out, " where "); for (i = 0; i < len; i++) { calcium_write(out, info->ext_vars[i]); calcium_write(out, " = "); _ca_ext_print(out, info->ext[i], info->ext_vars[i], info, ctx); if (i != len - 1) calcium_write(out, ", "); } } if (info->flags & CA_PRINT_N) calcium_write(out, "}"); } /* todo: move... */ } /* todo: something that doesn't run in quadratic time */ void _ca_ext_insert_extension(ca_ext_ptr ** extensions, slong * length, ca_ext_t x, ca_ctx_t ctx) { slong i, j; for (i = 0; i < *length; i++) { if (extensions[0][i] == x) return; } if (*length == 0) { extensions[0] = flint_malloc(4 * sizeof(ca_ext_ptr)); extensions[0][0] = x; *length = 1; } else { if (((*length + 1) & (*length)) == 0) extensions[0] = flint_realloc(extensions[0], ((*length + 1) * 2) * sizeof(ca_ext_ptr)); for (i = 0; i < *length; i++) { if (ca_ext_cmp_repr(extensions[0][i], x, ctx) < 0) { for (j = *length - 1; j >= i; j--) extensions[0][j + 1] = extensions[0][j]; extensions[0][i] = x; break; } else if (i == *length - 1) { extensions[0][*length] = x; } } *length = *length + 1; } } void _ca_all_extensions(ca_ext_ptr ** extensions, slong * length, const ca_t x, ca_ctx_t ctx); void _ca_ext_all_extensions(ca_ext_ptr ** extensions, slong * length, ca_ext_t x, ca_ctx_t ctx) { slong i; _ca_ext_insert_extension(extensions, length, x, ctx); if (!CA_EXT_IS_QQBAR(x)) { for (i = 0; i < CA_EXT_FUNC_NARGS(x); i++) _ca_all_extensions(extensions, length, CA_EXT_FUNC_ARGS(x) + i, ctx); } } void _ca_all_extensions(ca_ext_ptr ** extensions, slong * length, const ca_t x, ca_ctx_t ctx) { ca_field_srcptr K; slong i; if (CA_IS_SPECIAL(x)) { if (CA_IS_SIGNED_INF(x)) { ca_t sgn; sgn->field = x->field & ~CA_SPECIAL; sgn->elem = x->elem; _ca_all_extensions(extensions, length, sgn, ctx); } return; } K = CA_FIELD(x, ctx); for (i = 0; i < CA_FIELD_LENGTH(K); i++) { _ca_ext_all_extensions(extensions, length, CA_FIELD_EXT_ELEM(K, i), ctx); } } void ca_all_extensions(ca_ext_ptr ** extensions, slong * length, const ca_t x, ca_ctx_t ctx) { *extensions = NULL; *length = 0; _ca_all_extensions(extensions, length, x, ctx); } void ca_write(calcium_stream_t out, const ca_t x, ca_ctx_t ctx) { ca_print_info_t info; ca_ext_ptr * ext; slong i, len; char * all_vars; const char ** vars; ca_all_extensions(&ext, &len, x, ctx); all_vars = flint_malloc(15 * len); vars = flint_malloc(sizeof(char *) * len); for (i = 0; i < len; i++) { if (i < 26) { all_vars[15 * i] = 'a' + i; all_vars[15 * i + 1] = '\0'; } else { all_vars[15 * i] = 'a' + (i % 26); flint_sprintf(&all_vars[15 * i] + 1, "%wd", i / 26); } vars[i] = all_vars + 15 * i; } info.ext = ext; info.ext_len = len; info.ext_vars = vars; info.flags = ctx->options[CA_OPT_PRINT_FLAGS]; info.digits = ctx->options[CA_OPT_PRINT_FLAGS] / CA_PRINT_DIGITS; if (info.digits == 0) info.digits = 6; info.print_where = 1; _ca_print(out, x, &info, ctx); flint_free(all_vars); flint_free(vars); flint_free(ext); } char * ca_get_str(const ca_t x, ca_ctx_t ctx) { calcium_stream_t out; calcium_stream_init_str(out); ca_write(out, x, ctx); return out->s; } void ca_print(const ca_t x, ca_ctx_t ctx) { #if 1 char * s = ca_get_str(x, ctx); flint_printf("%s", s); flint_free(s); #else calcium_stream_t out; calcium_stream_init_file(out, stdout); ca_write(out, x, ctx); #endif } void ca_fprint(FILE * fp, const ca_t x, ca_ctx_t ctx) { calcium_stream_t out; calcium_stream_init_file(out, fp); ca_write(out, x, ctx); } calcium-0.4.1/ca/printn.c000066400000000000000000000012521407704557200152050ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_printn(const ca_t x, slong n, ca_ctx_t ctx) { ulong save_flags; save_flags = ctx->options[CA_OPT_PRINT_FLAGS]; ctx->options[CA_OPT_PRINT_FLAGS] = CA_PRINT_N | (CA_PRINT_DIGITS * n); ca_print(x, ctx); ctx->options[CA_OPT_PRINT_FLAGS] = save_flags; } calcium-0.4.1/ca/randtest.c000066400000000000000000000110161407704557200155160ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_randtest_same_nf(ca_t res, flint_rand_t state, const ca_t x, slong bits, slong den_bits, ca_ctx_t ctx) { if (n_randint(state, 2) || CA_IS_QQ(x, ctx)) { _ca_make_fmpq(res, ctx); fmpz_randtest(CA_FMPQ_NUMREF(res), state, bits); fmpz_randtest_not_zero(CA_FMPQ_DENREF(res), state, den_bits); fmpz_abs(CA_FMPQ_DENREF(res), CA_FMPQ_DENREF(res)); } else if (CA_FIELD_IS_NF(CA_FIELD(x, ctx))) { fmpq_poly_t p; fmpq_poly_init(p); fmpq_poly_randtest(p, state, qqbar_degree(CA_FIELD_NF_QQBAR(CA_FIELD(x, ctx))), bits); fmpz_randtest_not_zero(fmpq_poly_denref(p), state, den_bits); fmpz_abs(fmpq_poly_denref(p), fmpq_poly_denref(p)); fmpq_poly_canonicalise(p); ca_set(res, x, ctx); nf_elem_set_fmpq_poly(CA_NF_ELEM(res), p, CA_FIELD_NF(CA_FIELD(x, ctx))); ca_condense_field(res, ctx); fmpq_poly_clear(p); } else { flint_printf("ca_randtest_same_nf: not implemented\n"); flint_abort(); } } void ca_randtest_rational(ca_t res, flint_rand_t state, slong bits, ca_ctx_t ctx) { fmpq_t t; fmpq_init(t); fmpq_randtest(t, state, bits); ca_set_fmpq(res, t, ctx); fmpq_clear(t); } void ca_randtest_qqbar(ca_t res, flint_rand_t state, slong deg, slong bits, ca_ctx_t ctx) { qqbar_t q; qqbar_init(q); qqbar_randtest(q, state, deg, bits); ca_set_qqbar(res, q, ctx); qqbar_clear(q); } void ca_randtest(ca_t res, flint_rand_t state, slong len, slong bits, ca_ctx_t ctx) { if (len == 0 || n_randint(state, 2)) { switch (n_randint(state, 10)) { case 0: ca_randtest_qqbar(res, state, 2, FLINT_MAX(bits, 2), ctx); break; case 1: ca_i(res, ctx); break; case 2: ca_pi(res, ctx); break; case 3: ca_pi_i(res, ctx); break; case 4: ca_set_si(res, -6 + (slong) n_randint(state, 13), ctx); ca_sqrt(res, res, ctx); break; default: ca_randtest_rational(res, state, bits, ctx); break; } } else if (n_randint(state, 10) != 0) { ca_t t; ca_init(t, ctx); ca_randtest(t, state, len - 1, bits, ctx); ca_randtest(res, state, len - 1, bits, ctx); switch (n_randint(state, 4)) { case 0: ca_add(res, res, t, ctx); break; case 1: ca_sub(res, res, t, ctx); break; case 2: ca_mul(res, res, t, ctx); break; default: if (ca_check_is_zero(t, ctx) == T_FALSE) ca_div(res, res, t, ctx); break; } ca_clear(t, ctx); } else { ca_randtest(res, state, len - 1, bits, ctx); switch (n_randint(state, 2)) { case 0: ca_exp(res, res, ctx); break; default: if (ca_check_is_zero(res, ctx) != T_FALSE) ca_set_ui(res, 2, ctx); ca_log(res, res, ctx); break; } } } void ca_randtest_special(ca_t res, flint_rand_t state, slong len, slong bits, ca_ctx_t ctx) { if (n_randint(state, 4) == 0) { switch (n_randint(state, 7)) { case 0: ca_pos_inf(res, ctx); break; case 1: ca_neg_inf(res, ctx); break; case 2: ca_pos_i_inf(res, ctx); break; case 3: ca_neg_i_inf(res, ctx); /* todo: other signed infs? */ break; case 4: ca_uinf(res, ctx); break; case 5: ca_undefined(res, ctx); break; default: ca_unknown(res, ctx); } } else { ca_randtest(res, state, len, bits, ctx); } } calcium-0.4.1/ca/re.c000066400000000000000000000025571407704557200143120ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_re(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (CA_IS_UNKNOWN(x)) ca_unknown(res, ctx); else ca_undefined(res, ctx); } else if (CA_IS_QQ(x, ctx)) { ca_set(res, x, ctx); } else if (CA_IS_QQ_I(x, ctx)) { const fmpz *n, *d; fmpq_t t; n = QNF_ELEM_NUMREF(CA_NF_ELEM(x)); d = QNF_ELEM_DENREF(CA_NF_ELEM(x)); fmpq_init(t); fmpq_set_fmpz_frac(t, n, d); ca_set_fmpq(res, t, ctx); fmpq_clear(t); } else if (ca_check_is_real(x, ctx) == T_TRUE) /* todo: avoid duplicate computations with is_real/is_imaginary */ { ca_set(res, x, ctx); } else if (ca_check_is_imaginary(x, ctx) == T_TRUE) { ca_zero(res, ctx); } else { _ca_make_field_element(res, _ca_ctx_get_field_fx(ctx, CA_Re, x), ctx); fmpz_mpoly_q_gen(CA_MPOLY_Q(res), 0, CA_MCTX_1(ctx)); } } calcium-0.4.1/ca/rewrite_complex_normal_form.c000066400000000000000000000257661407704557200215160ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_vec.h" /* todo */ void ca_rewrite_complex_normal_form(ca_t res, const ca_t x, int deep, ca_ctx_t ctx); /* todo */ void ca_set_ext(ca_t res, ca_ext_srcptr ext, ca_ctx_t ctx); /* todo */ ulong qqbar_try_as_cyclotomic(qqbar_t zeta, fmpq_poly_t poly, const qqbar_t x); /* todo: Re, Im, Abs, Sgn ... */ void ca_rewrite_ext_complex_normal_form(ca_t res, ca_ext_ptr ext, int deep, ca_ctx_t ctx) { switch (CA_EXT_HEAD(ext)) { case CA_QQBar: if (qqbar_is_i(CA_EXT_QQBAR(ext))) { ca_set_ext(res, ext, ctx); } else if (qqbar_is_root_of_unity(NULL, NULL, CA_EXT_QQBAR(ext))) { ca_set_ext(res, ext, ctx); } else { fmpq_poly_t poly; qqbar_t zeta; ulong q; qqbar_init(zeta); fmpq_poly_init(poly); q = qqbar_try_as_cyclotomic(zeta, poly, CA_EXT_QQBAR(ext)); if (q != 0) { ca_set_qqbar(res, zeta, ctx); ca_fmpq_poly_evaluate(res, poly, res, ctx); } else { ca_set_ext(res, ext, ctx); } qqbar_clear(zeta); fmpq_poly_clear(poly); } break; case CA_Re: case CA_Im: case CA_Conjugate: case CA_Abs: case CA_Sign: case CA_Arg: { ca_t t, u; truth_t is_zero; ca_init(t, ctx); ca_init(u, ctx); if (deep) ca_rewrite_complex_normal_form(t, CA_EXT_FUNC_ARGS(ext), deep, ctx); else ca_set(t, CA_EXT_FUNC_ARGS(ext), ctx); switch (CA_EXT_HEAD(ext)) { case CA_Re: ca_conj_deep(u, t, ctx); ca_add(res, t, u, ctx); ca_div_ui(res, res, 2, ctx); break; case CA_Im: ca_conj_deep(u, t, ctx); ca_sub(res, t, u, ctx); ca_div_ui(res, res, 2, ctx); ca_neg_i(t, ctx); ca_mul(res, res, t, ctx); break; case CA_Conjugate: ca_conj_deep(res, t, ctx); break; case CA_Abs: ca_conj_deep(u, t, ctx); ca_mul(t, t, u, ctx); ca_sqrt(res, t, ctx); break; case CA_Sign: is_zero = ca_check_is_zero(t, ctx); if (is_zero == T_TRUE) { ca_zero(res, ctx); } else if (is_zero == T_FALSE) { ca_conj_deep(u, t, ctx); ca_mul(u, t, u, ctx); ca_sqrt(u, u, ctx); /* todo: division by zero is impossible; optimizations here */ ca_div(res, t, u, ctx); } else { ca_sgn(res, t, ctx); } break; case CA_Arg: is_zero = ca_check_is_zero(t, ctx); if (is_zero == T_TRUE) { ca_zero(res, ctx); } else if (is_zero == T_FALSE) { /* todo: better to create two logs? */ ca_conj_deep(u, t, ctx); ca_mul(u, t, u, ctx); ca_sqrt(u, u, ctx); ca_div(u, t, u, ctx); ca_log(u, u, ctx); ca_neg_i(t, ctx); ca_mul(res, t, u, ctx); } else { ca_arg(res, t, ctx); } break; default: flint_abort(); } ca_clear(t, ctx); ca_clear(u, ctx); } break; /* sin(x) = (exp(ix) - 1/exp(ix))/(2i) */ /* cos(x) = (exp(ix) + 1/exp(ix))/2 */ /* tan(x) = 2i/(exp(2ix)+1) */ case CA_Sin: case CA_Cos: case CA_Tan: { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); if (deep) ca_rewrite_complex_normal_form(t, CA_EXT_FUNC_ARGS(ext), deep, ctx); else ca_set(t, CA_EXT_FUNC_ARGS(ext), ctx); if (CA_EXT_HEAD(ext) == CA_Sin) ca_sin_cos_exponential(res, NULL, t, ctx); else if (CA_EXT_HEAD(ext) == CA_Cos) ca_sin_cos_exponential(NULL, res, t, ctx); else { ca_sin_cos_exponential(t, u, t, ctx); ca_div(res, t, u, ctx); } ca_clear(t, ctx); ca_clear(u, ctx); } break; case CA_Atan: case CA_Asin: case CA_Acos: { ca_t t; ca_init(t, ctx); if (deep) ca_rewrite_complex_normal_form(t, CA_EXT_FUNC_ARGS(ext), deep, ctx); else ca_set(t, CA_EXT_FUNC_ARGS(ext), ctx); if (CA_EXT_HEAD(ext) == CA_Asin) ca_asin_logarithm(res, t, ctx); else if (CA_EXT_HEAD(ext) == CA_Acos) ca_acos_logarithm(res, t, ctx); else ca_atan_logarithm(res, t, ctx); ca_clear(t, ctx); } break; case CA_Sqrt: case CA_Exp: case CA_Log: if (deep) { ca_rewrite_complex_normal_form(res, CA_EXT_FUNC_ARGS(ext), deep, ctx); if (ca_equal_repr(res, CA_EXT_FUNC_ARGS(ext), ctx)) { ca_set_ext(res, ext, ctx); } else { switch (CA_EXT_HEAD(ext)) { case CA_Exp: ca_exp(res, res, ctx); break; case CA_Log: ca_log(res, res, ctx); break; case CA_Sqrt: ca_sqrt(res, res, ctx); break; default: flint_abort(); } } } else { ca_set_ext(res, ext, ctx); } break; default: /* todo: deep */ ca_set_ext(res, ext, ctx); } } void ca_rewrite_complex_normal_form(ca_t res, const ca_t x, int deep, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (CA_IS_SIGNED_INF(x)) { ca_sgn(res, x, ctx); ca_rewrite_complex_normal_form(res, res, deep, ctx); if (!ca_is_unknown(res, ctx)) res->field |= CA_INF; } else { ca_set(res, x, ctx); } } else if (CA_IS_QQ(x, ctx) || CA_IS_QQ_I(x, ctx)) { ca_set(res, x, ctx); } else { ca_field_ptr K = CA_FIELD(x, ctx); if (CA_FIELD_IS_NF(K)) { if (qqbar_is_root_of_unity(NULL, NULL, CA_FIELD_NF_QQBAR(K))) { ca_set(res, x, ctx); } else { fmpq_poly_t poly, xpoly; qqbar_t zeta; ulong q; qqbar_init(zeta); fmpq_poly_init(poly); q = qqbar_try_as_cyclotomic(zeta, poly, CA_FIELD_NF_QQBAR(K)); if (q != 0) { fmpq_poly_init(xpoly); nf_elem_get_fmpq_poly(xpoly, CA_NF_ELEM(x), CA_FIELD_NF(K)); ca_set_qqbar(res, zeta, ctx); ca_fmpq_poly_evaluate(res, poly, res, ctx); ca_fmpq_poly_evaluate(res, xpoly, res, ctx); fmpq_poly_clear(xpoly); } else { ca_set(res, x, ctx); } qqbar_clear(zeta); fmpq_poly_clear(poly); } } else if (0) { ca_set(res, x, ctx); } else { slong nvars; int * used; slong i; ca_ptr cext; nvars = CA_FIELD_LENGTH(K); used = flint_calloc(nvars, sizeof(int)); cext = _ca_vec_init(nvars, ctx); fmpz_mpoly_q_used_vars(used, CA_MPOLY_Q(x), CA_FIELD_MCTX(K, ctx)); for (i = 0; i < nvars; i++) { if (used[i]) { ca_rewrite_ext_complex_normal_form(cext + i, CA_FIELD_EXT_ELEM(K, i), deep, ctx); } } ca_fmpz_mpoly_q_evaluate_no_division_by_zero(res, CA_MPOLY_Q(x), cext, CA_FIELD_MCTX(K, ctx), ctx); _ca_vec_clear(cext, nvars, ctx); /* Root of unity hack: introduce artificial root of unity to force simplifications. This should not be necessary; cases where it helps are a sign that we are not finding all exponential relations. */ if (0 && !CA_IS_SPECIAL(res) && !CA_FIELD_IS_QQ(CA_FIELD(res, ctx)) && !CA_FIELD_IS_NF(CA_FIELD(res, ctx))) { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); ca_pi_i(t, ctx); ca_div_ui(t, t, 12, ctx); ca_exp(t, t, ctx); ca_add(u, res, t, ctx); ca_sub(u, u, t, ctx); if (ca_cmp_repr(u, res, ctx) < 0) ca_swap(res, u, ctx); ca_clear(t, ctx); ca_clear(u, ctx); } flint_free(used); } } } calcium-0.4.1/ca/set.c000066400000000000000000000025711407704557200144730ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_set(ca_t res, const ca_t x, ca_ctx_t ctx) { if (res != x) { ulong field_flags; ca_field_srcptr field; field_flags = x->field; field = (ca_field_srcptr) (x->field & ~CA_SPECIAL); /* for Undefined, Unknown, UnsignedInfinity */ if (field == NULL) { ca_clear(res, ctx); res->field = field_flags; return; } _ca_make_field_element(res, field, ctx); res->field = field_flags; /* set special flags */ if (field != NULL) { if (CA_FIELD_IS_QQ(field)) { fmpq_set(CA_FMPQ(res), CA_FMPQ(x)); } else if (CA_FIELD_IS_NF(field)) { nf_elem_set(CA_NF_ELEM(res), CA_NF_ELEM(x), CA_FIELD_NF(field)); } else { fmpz_mpoly_q_set(CA_MPOLY_Q(res), CA_MPOLY_Q(x), CA_FIELD_MCTX(field, ctx)); } } } } calcium-0.4.1/ca/set_d.c000066400000000000000000000015521407704557200147740ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_set_d(ca_t res, double x, ca_ctx_t ctx) { arf_t t; arf_init(t); arf_set_d(t, x); if (arf_is_finite(t)) { _ca_make_fmpq(res, ctx); arf_get_fmpq(CA_FMPQ(res), t); } else { if (arf_is_pos_inf(t)) ca_pos_inf(res, ctx); else if (arf_is_neg_inf(t)) ca_neg_inf(res, ctx); else ca_unknown(res, ctx); /* or undefined? */ } /* no need to free t */ } calcium-0.4.1/ca/set_d_d.c000066400000000000000000000014001407704557200152670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_set_d_d(ca_t res, double x, double y, ca_ctx_t ctx) { if (y == 0.0) { ca_set_d(res, x, ctx); } else { ca_t t; ca_init(t, ctx); ca_set_d(t, y, ctx); ca_i(res, ctx); ca_mul(res, res, t, ctx); ca_set_d(t, x, ctx); ca_add(res, res, t, ctx); ca_clear(t, ctx); } } calcium-0.4.1/ca/set_fexpr.c000066400000000000000000000214141407704557200156740ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_vec.h" #include "fexpr.h" #include "fexpr_builtin.h" #define BINARY_OP(ca_func) \ if (nargs == 2) \ { \ ca_init(t, ctx); \ fexpr_view_arg(arg, expr, 0); \ success = _ca_set_fexpr(res, inputs, outputs, arg, ctx); \ if (success) \ { \ fexpr_view_next(arg); \ success = _ca_set_fexpr(t, inputs, outputs, arg, ctx); \ if (success) \ ca_func(res, res, t, ctx); \ } \ ca_clear(t, ctx); \ return success; \ } \ return 0; \ #define UNARY_OP(ca_func) \ if (nargs == 1) \ { \ fexpr_view_arg(arg, expr, 0); \ success = _ca_set_fexpr(res, inputs, outputs, arg, ctx); \ if (success) \ ca_func(res, res, ctx); \ return success; \ } \ return 0; \ int _ca_set_fexpr(ca_t res, fexpr_vec_t inputs, ca_vec_t outputs, const fexpr_t expr, ca_ctx_t ctx) { if (fexpr_is_integer(expr)) { _ca_make_fmpq(res, ctx); fexpr_get_fmpz(CA_FMPQ_NUMREF(res), expr); fmpz_one(CA_FMPQ_DENREF(res)); return 1; } if (fexpr_is_any_builtin_symbol(expr)) { slong op = FEXPR_BUILTIN_ID(expr->data[0]); switch (op) { case FEXPR_Pi: ca_pi(res, ctx); return 1; case FEXPR_NumberI: ca_i(res, ctx); return 1; case FEXPR_NumberE: ca_one(res, ctx); ca_exp(res, res, ctx); return 1; case FEXPR_Euler: ca_euler(res, ctx); return 1; case FEXPR_GoldenRatio: ca_sqrt_ui(res, 5, ctx); ca_add_ui(res, res, 1, ctx); ca_div_ui(res, res, 2, ctx); return 1; case FEXPR_Infinity: ca_pos_inf(res, ctx); return 1; case FEXPR_UnsignedInfinity: ca_uinf(res, ctx); return 1; case FEXPR_Undefined: ca_undefined(res, ctx); return 1; case FEXPR_Unknown: ca_unknown(res, ctx); return 1; } return 0; } if (fexpr_is_symbol(expr)) { slong i, num_defs; num_defs = inputs->length; /* Treat local definitions as a stack, more recent ones overriding older ones */ for (i = num_defs - 1; i >= 0; i--) { if (fexpr_equal(expr, fexpr_vec_entry(inputs, i))) { ca_set(res, ca_vec_entry(outputs, i), ctx); return 1; } } return 0; } if (fexpr_is_any_builtin_call(expr)) { fexpr_t func, arg; slong op, i, nargs; int success; ca_t t; nargs = fexpr_nargs(expr); fexpr_view_func(func, expr); op = FEXPR_BUILTIN_ID(func->data[0]); /* Parse local definitions */ if (op == FEXPR_Where) { slong num_previous_defs; num_previous_defs = inputs->length; success = 1; /* Parse in reverse order; this assumes definitions are in the form x = f(y,z), y = g(z), z = h which is what ca_get_fexpr currently generates. Should this work in both directions (or any order)? */ for (i = nargs - 1; i >= 1; i--) { fexpr_t defn, symbol, value; fexpr_view_arg(defn, expr, i); if (!fexpr_is_builtin_call(defn, FEXPR_Def) || fexpr_nargs(defn) != 2) { success = 0; break; } fexpr_view_arg(symbol, defn, 0); fexpr_view_arg(value, defn, 1); success = _ca_set_fexpr(res, inputs, outputs, value, ctx); if (!success) break; fexpr_vec_append(inputs, symbol); ca_vec_append(outputs, res, ctx); } if (success) { fexpr_view_arg(arg, expr, 0); success = _ca_set_fexpr(res, inputs, outputs, arg, ctx); } /* We are done with the local definitions, so erase anything new. */ fexpr_vec_set_length(inputs, num_previous_defs); ca_vec_set_length(outputs, num_previous_defs, ctx); return success; } switch (op) { /* todo: generalize to non-algebraics; handle large decimals efficiently */ case FEXPR_Decimal: case FEXPR_PolynomialRootIndexed: case FEXPR_PolynomialRootNearest: case FEXPR_AlgebraicNumberSerialized: { qqbar_t a; qqbar_init(a); success = qqbar_set_fexpr(a, expr); if (success) ca_set_qqbar(res, a, ctx); qqbar_clear(a); return success; } case FEXPR_Pos: UNARY_OP(ca_set) case FEXPR_Neg: UNARY_OP(ca_neg) case FEXPR_Sub: BINARY_OP(ca_sub) case FEXPR_Div: BINARY_OP(ca_div) case FEXPR_Pow: BINARY_OP(ca_pow) case FEXPR_Sqrt: UNARY_OP(ca_sqrt) case FEXPR_Exp: UNARY_OP(ca_exp) case FEXPR_Log: UNARY_OP(ca_log) case FEXPR_Sin: UNARY_OP(ca_sin) case FEXPR_Cos: UNARY_OP(ca_cos) case FEXPR_Tan: UNARY_OP(ca_tan) case FEXPR_Cot: UNARY_OP(ca_cot) case FEXPR_Atan: UNARY_OP(ca_atan) case FEXPR_Acos: UNARY_OP(ca_acos) case FEXPR_Asin: UNARY_OP(ca_asin) case FEXPR_Sign: UNARY_OP(ca_sgn) case FEXPR_Csgn: UNARY_OP(ca_csgn) case FEXPR_Arg: UNARY_OP(ca_arg) case FEXPR_Abs: UNARY_OP(ca_abs) case FEXPR_Re: UNARY_OP(ca_re) case FEXPR_Im: UNARY_OP(ca_im) case FEXPR_Conjugate: UNARY_OP(ca_conj) case FEXPR_Floor: UNARY_OP(ca_floor) case FEXPR_Ceil: UNARY_OP(ca_ceil) case FEXPR_Gamma: UNARY_OP(ca_gamma) case FEXPR_Erf: UNARY_OP(ca_erf) case FEXPR_Erfc: UNARY_OP(ca_erfc) case FEXPR_Erfi: UNARY_OP(ca_erfi) case FEXPR_Add: if (nargs == 0) { ca_zero(res, ctx); return 1; } fexpr_view_arg(arg, expr, 0); success = _ca_set_fexpr(res, inputs, outputs, arg, ctx); if (success && nargs > 1) { /* todo: divide and conquer for large nargs? */ ca_init(t, ctx); for (i = 1; i < nargs && success; i++) { fexpr_view_next(arg); success = _ca_set_fexpr(t, inputs, outputs, arg, ctx); if (success) ca_add(res, res, t, ctx); } ca_clear(t, ctx); } return success; case FEXPR_Mul: if (nargs == 0) { ca_one(res, ctx); return 1; } fexpr_view_arg(arg, expr, 0); success = _ca_set_fexpr(res, inputs, outputs, arg, ctx); if (success && nargs > 1) { /* todo: divide and conquer for large nargs? */ ca_init(t, ctx); for (i = 1; i < nargs && success; i++) { fexpr_view_next(arg); success = _ca_set_fexpr(t, inputs, outputs, arg, ctx); if (success) ca_mul(res, res, t, ctx); } ca_clear(t, ctx); } return success; } } return 0; } int ca_set_fexpr(ca_t res, const fexpr_t expr, ca_ctx_t ctx) { int success; fexpr_vec_t inputs; ca_vec_t outputs; fexpr_vec_init(inputs, 0); ca_vec_init(outputs, 0, ctx); success = _ca_set_fexpr(res, inputs, outputs, expr, ctx); fexpr_vec_clear(inputs); ca_vec_clear(outputs, ctx); return success; } calcium-0.4.1/ca/set_fmpq.c000066400000000000000000000010111407704557200155020ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_set_fmpq(ca_t x, const fmpq_t v, ca_ctx_t ctx) { _ca_make_fmpq(x, ctx); fmpq_set(CA_FMPQ(x), v); } calcium-0.4.1/ca/set_fmpz.c000066400000000000000000000010611407704557200155200ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_set_fmpz(ca_t x, const fmpz_t v, ca_ctx_t ctx) { _ca_make_fmpq(x, ctx); fmpz_set(CA_FMPQ_NUMREF(x), v); fmpz_one(CA_FMPQ_DENREF(x)); } calcium-0.4.1/ca/set_qqbar.c000066400000000000000000000244671407704557200156710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" #define FACTOR_SMOOTH_BOUND 32 /* Write |n| = A * B^2 */ static void _fmpz_factor_square_root(fmpz_t A, fmpz_t B, const fmpz_t n, slong smooth_bound) { fmpz_factor_t fac; fmpz_t t; slong i; fmpz_factor_init(fac); fmpz_factor_smooth(fac, n, smooth_bound, -1); /* -1 => no primality test */ fmpz_one(A); fmpz_one(B); fmpz_init(t); for (i = 0; i < fac->num; i++) { if (fac->exp[i] == 1) { fmpz_mul(A, A, fac->p + i); } else if (fac->exp[i] == 2) { fmpz_mul(B, B, fac->p + i); } else { fmpz_pow_ui(t, fac->p + i, fac->exp[i] / 2); fmpz_mul(B, B, t); if (fac->exp[i] % 2) fmpz_mul(A, A, fac->p + i); } } fmpz_factor_clear(fac); fmpz_clear(t); } ca_field_ptr ca_field_cache_lookup_qqbar(ca_field_cache_t cache, const qqbar_t x, ca_ctx_t ctx); ca_field_ptr ca_ctx_get_field_qqbar(ca_ctx_t ctx, const qqbar_t x) { ca_ext_t ext; ca_ext_struct * ext_ptr[1]; ca_field_ptr field; field = ca_field_cache_lookup_qqbar(CA_CTX_FIELD_CACHE(ctx), x, ctx); if (field == NULL) { /* todo: shallow copy */ ca_ext_init_qqbar(ext, x, ctx); ext_ptr[0] = ca_ext_cache_insert(CA_CTX_EXT_CACHE(ctx), ext, ctx); field = ca_field_cache_insert_ext(CA_CTX_FIELD_CACHE(ctx), ext_ptr, 1, ctx); ca_ext_clear(ext, ctx); } return field; } #if 0 /* Find if sqrt(A) is cached; otherwise create new field */ /* Todo: fast search table */ slong ca_ctx_get_quadratic_field(ca_ctx_t ctx, const fmpz_t A) { qqbar_t T; slong i; for (i = 0; i < ctx->fields_len; i++) { if (ctx->fields[i].type == CA_FIELD_TYPE_NF) { const qqbar_struct * v; v = CA_FIELD_NF_QQBAR(ctx->fields + i); if (qqbar_degree(v) == 2) { if (fmpz_is_one(QQBAR_COEFFS(v) + 2) && fmpz_is_zero(QQBAR_COEFFS(v) + 1) && (fmpz_cmpabs(QQBAR_COEFFS(v), A) == 0) && !fmpz_equal(QQBAR_COEFFS(v), A)) { if (fmpz_sgn(A) < 0) { if (qqbar_sgn_im(v) > 0) return i; } else { if (qqbar_sgn_re(v) >= 0) return i; } } } } } i = ctx->fields_len; if (i >= ctx->fields_alloc) { ctx->fields = (ca_field_struct *) flint_realloc(ctx->fields, sizeof(ca_field_struct) * 2 * ctx->fields_alloc); ctx->fields_alloc = 2 * ctx->fields_alloc; } ctx->fields_len = i + 1; qqbar_init(T); qqbar_set_fmpz(T, A); qqbar_sqrt(T, T); ca_field_init_nf(ctx->fields + i, T); qqbar_clear(T); return i; } #else ca_field_srcptr ca_ctx_get_quadratic_field(ca_ctx_t ctx, const fmpz_t A) { ca_field_srcptr res; qqbar_t x; qqbar_init(x); #if 0 qqbar_set_fmpz(x, A); qqbar_sqrt(x, x); #else fmpz_poly_fit_length(QQBAR_POLY(x), 3); _fmpz_poly_set_length(QQBAR_POLY(x), 3); fmpz_neg(QQBAR_COEFFS(x) + 0, A); fmpz_zero(QQBAR_COEFFS(x) + 1); fmpz_one(QQBAR_COEFFS(x) + 2); acb_set_fmpz(QQBAR_ENCLOSURE(x), A); acb_sqrt(QQBAR_ENCLOSURE(x), QQBAR_ENCLOSURE(x), QQBAR_DEFAULT_PREC); #endif res = ca_ctx_get_field_qqbar(ctx, x); qqbar_clear(x); return res; } #endif ca_field_srcptr ca_ctx_get_cyclotomic_field(ca_ctx_t ctx, ulong n) { ca_field_srcptr res; qqbar_t x; qqbar_init(x); qqbar_root_of_unity(x, 1, n); res = ca_ctx_get_field_qqbar(ctx, x); qqbar_clear(x); return res; } static int fmpz_discr_3(fmpz_t t, const fmpz_t D) { if (fmpz_sgn(D) < 0) return 0; if (!fmpz_divisible_si(D, 3)) return 0; fmpz_divexact_ui(t, D, 3); if (!fmpz_is_square(t)) return 0; return 1; } void ca_set_qqbar(ca_t res, const qqbar_t x, ca_ctx_t ctx) { slong d; d = qqbar_degree(x); if (d == 1) { _ca_make_fmpq(res, ctx); qqbar_get_fmpq(CA_FMPQ(res), x); } else if (d == 2) { const fmpz *a, *b, *c; fmpz_t D, t; fmpz * res_num; fmpz * res_den; a = QQBAR_COEFFS(x) + 2; b = QQBAR_COEFFS(x) + 1; c = QQBAR_COEFFS(x) + 0; /* x = (-b +/- sqrt(b^2 - 4ac))/(2a) */ fmpz_init(D); fmpz_init(t); fmpz_mul(D, a, c); fmpz_mul_2exp(D, D, 2); fmpz_submul(D, b, b); /* -D is a square <=> element of Q(i) */ if (fmpz_is_square(D)) { fmpz_sqrt(D, D); _ca_make_field_element(res, ctx->field_qq_i, ctx); res_num = QNF_ELEM_NUMREF(CA_NF_ELEM(res)); res_den = QNF_ELEM_DENREF(CA_NF_ELEM(res)); if (qqbar_sgn_im(x) > 0) fmpz_set(res_num + 1, D); else fmpz_neg(res_num + 1, D); fmpz_neg(res_num, b); fmpz_mul_2exp(res_den, a, 1); /* todo: is gcd avoidable? */ /* todo: at least use fmpz_gcd3 */ fmpz_gcd(D, res_num, res_num + 1); fmpz_gcd(D, D, res_den); if (!fmpz_is_one(D)) { fmpz_divexact(res_num, res_num, D); fmpz_divexact(res_num + 1, res_num + 1, D); fmpz_divexact(res_den, res_den, D); } } else if (fmpz_discr_3(t, D)) /* Special case for Q(zeta_3) */ { ca_field_srcptr K; fmpz_sqrt(D, t); K = ca_ctx_get_cyclotomic_field(ctx, 3); _ca_make_field_element(res, K, ctx); res_num = QNF_ELEM_NUMREF(CA_NF_ELEM(res)); res_den = QNF_ELEM_DENREF(CA_NF_ELEM(res)); if (qqbar_sgn_im(x) < 0) { fmpz_neg(D, D); } fmpz_sub(res_num, D, b); fmpz_mul_2exp(res_num + 1, D, 1); fmpz_mul_2exp(res_den, a, 1); /* todo: is gcd avoidable? */ /* todo: at least use fmpz_gcd3 */ fmpz_gcd(D, res_num, res_num + 1); fmpz_gcd(D, D, res_den); if (!fmpz_is_one(D)) { fmpz_divexact(res_num, res_num, D); fmpz_divexact(res_num + 1, res_num + 1, D); fmpz_divexact(res_den, res_den, D); } } else { fmpz_t A, B; ca_field_srcptr field; fmpz_neg(D, D); fmpz_init(A); fmpz_init(B); /* sqrt(|D|) = A * B^2 => sqrt(D) = sqrt(A) * B (D > 0) sqrt(-A) * B (D < 0) */ _fmpz_factor_square_root(A, B, D, FACTOR_SMOOTH_BOUND); if (fmpz_sgn(D) < 0) fmpz_neg(A, A); field = ca_ctx_get_quadratic_field(ctx, A); _ca_make_field_element(res, field, ctx); res_num = QNF_ELEM_NUMREF(CA_NF_ELEM(res)); res_den = QNF_ELEM_DENREF(CA_NF_ELEM(res)); /* x = (-b +/- B*sqrt(A))/(2a) */ fmpz_neg(res_num, b); fmpz_mul_2exp(res_den, a, 1); /* determine the correct sign */ { if (fmpz_sgn(D) < 0) { if (qqbar_sgn_im(x) > 0) fmpz_set(res_num + 1, B); else fmpz_neg(res_num + 1, B); } else if (fmpz_is_zero(b)) { if (qqbar_sgn_re(x) > 0) fmpz_set(res_num + 1, B); else fmpz_neg(res_num + 1, B); } else { arb_t r1, r2; slong prec; arb_init(r1); arb_init(r2); for (prec = 64; ; prec *= 2) { arb_sqrt_fmpz(r1, A, prec); arb_mul_fmpz(r1, r1, B, prec); arb_add_fmpz(r2, r1, b, prec); arb_neg(r2, r2); arb_sub_fmpz(r1, r1, b, prec); arb_div_fmpz(r1, r1, a, prec); arb_div_fmpz(r2, r2, a, prec); arb_mul_2exp_si(r1, r1, -1); arb_mul_2exp_si(r2, r2, -1); if (arb_overlaps(r1, acb_realref(QQBAR_ENCLOSURE(x))) && !arb_overlaps(r2, acb_realref(QQBAR_ENCLOSURE(x)))) { fmpz_set(res_num + 1, B); break; } if (arb_overlaps(r2, acb_realref(QQBAR_ENCLOSURE(x))) && !arb_overlaps(r1, acb_realref(QQBAR_ENCLOSURE(x)))) { fmpz_neg(res_num + 1, B); break; } } arb_clear(r1); arb_clear(r2); } } /* todo: use fmpz_gcd3 */ fmpz_gcd(D, res_num, res_num + 1); fmpz_gcd(D, D, res_den); if (!fmpz_is_one(D)) { fmpz_divexact(res_num, res_num, D); fmpz_divexact(res_num + 1, res_num + 1, D); fmpz_divexact(res_den, res_den, D); } fmpz_clear(A); fmpz_clear(B); } fmpz_clear(D); fmpz_clear(t); } else { ca_field_srcptr field; field = ca_ctx_get_field_qqbar(ctx, x); _ca_make_field_element(res, field, ctx); nf_elem_gen(CA_NF_ELEM(res), CA_FIELD_NF(field)); } } calcium-0.4.1/ca/set_si.c000066400000000000000000000010531407704557200151600ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_set_si(ca_t x, slong v, ca_ctx_t ctx) { _ca_make_fmpq(x, ctx); fmpz_set_si(CA_FMPQ_NUMREF(x), v); fmpz_one(CA_FMPQ_DENREF(x)); } calcium-0.4.1/ca/set_ui.c000066400000000000000000000010531407704557200151620ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_set_ui(ca_t x, ulong v, ca_ctx_t ctx) { _ca_make_fmpq(x, ctx); fmpz_set_ui(CA_FMPQ_NUMREF(x), v); fmpz_one(CA_FMPQ_DENREF(x)); } calcium-0.4.1/ca/sgn.c000066400000000000000000000025141407704557200144640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_sgn(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (CA_IS_SIGNED_INF(x)) { ca_set(res, x, ctx); res->field &= ~CA_INF; } else if (CA_IS_UNKNOWN(x)) { ca_unknown(res, ctx); } else { ca_undefined(res, ctx); } return; } else if (CA_IS_QQ(x, ctx)) { ca_set_si(res, fmpz_sgn(fmpq_numref(CA_FMPQ(x))), ctx); } else { qqbar_t t; qqbar_init(t); if (ca_get_qqbar(t, x, ctx)) { qqbar_sgn(t, t); if (qqbar_within_limits(t, ctx->options[CA_OPT_QQBAR_DEG_LIMIT], 0)) ca_set_qqbar(res, t, ctx); else _ca_function_fx(res, CA_Sign, x, ctx); } else { _ca_function_fx(res, CA_Sign, x, ctx); } qqbar_clear(t); } } calcium-0.4.1/ca/sin_cos.c000066400000000000000000000243161407704557200153360ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_vec.h" void ca_sin_cos_special(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx) { truth_t t1, t2; if (ca_check_is_signed_inf(x, ctx) == T_TRUE) { t1 = ca_check_is_pos_i_inf(x, ctx); if (t1 == T_TRUE) { if (res1 != NULL) ca_pos_i_inf(res1, ctx); if (res2 != NULL) ca_pos_inf(res2, ctx); return; } t2 = ca_check_is_neg_i_inf(x, ctx); if (t2 == T_TRUE) { if (res1 != NULL) ca_neg_i_inf(res1, ctx); if (res2 != NULL) ca_pos_inf(res2, ctx); return; } if (t1 == T_FALSE && t2 == T_FALSE) { if (res1 != NULL) ca_undefined(res1, ctx); if (res2 != NULL) ca_undefined(res2, ctx); return; } } if (ca_check_is_undefined(x, ctx) == T_TRUE || ca_check_is_uinf(x, ctx) == T_TRUE) { if (res1 != NULL) ca_undefined(res1, ctx); if (res2 != NULL) ca_undefined(res2, ctx); return; } if (res1 != NULL) ca_unknown(res1, ctx); if (res2 != NULL) ca_unknown(res2, ctx); } void ca_sin_cos_exponential(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx) { ca_t ix, y, t; if (CA_IS_SPECIAL(x)) { ca_sin_cos_special(res1, res2, x, ctx); return; } ca_init(ix, ctx); ca_init(y, ctx); ca_init(t, ctx); ca_i(ix, ctx); ca_mul(ix, x, ix, ctx); ca_exp(y, ix, ctx); ca_inv(t, y, ctx); if (res2 != NULL) { ca_add(res2, y, t, ctx); ca_div_ui(res2, res2, 2, ctx); } if (res1 != NULL) { ca_sub(res1, y, t, ctx); ca_div_ui(res1, res1, 2, ctx); ca_neg_i(t, ctx); ca_mul(res1, res1, t, ctx); } ca_clear(ix, ctx); ca_clear(y, ctx); ca_clear(t, ctx); } void ca_sin_cos_direct(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx) { ca_t t, pi; fmpq_t v; if (CA_IS_SPECIAL(x)) { ca_sin_cos_special(res1, res2, x, ctx); return; } ca_init(t, ctx); ca_init(pi, ctx); fmpq_init(v); ca_pi(pi, ctx); ca_div(t, x, pi, ctx); if (ca_get_fmpq(v, t, ctx)) { /* For now, only convert trivial values */ if (fmpz_cmp_ui(fmpq_denref(v), 6) <= 0 && !fmpz_equal_ui(fmpq_denref(v), 5)) { slong p, q; qqbar_t a; q = fmpz_get_ui(fmpq_denref(v)); p = fmpz_fdiv_ui(fmpq_numref(v), 2 * q); qqbar_init(a); if (res1 != NULL) { qqbar_sin_pi(a, p, q); ca_set_qqbar(res1, a, ctx); } if (res2 != NULL) { qqbar_cos_pi(a, p, q); ca_set_qqbar(res2, a, ctx); } qqbar_clear(a); } else { ca_mul_fmpq(t, pi, v, ctx); if (fmpq_sgn(v) > 0) { if (res1 != NULL) _ca_function_fx(res1, CA_Sin, t, ctx); if (res2 != NULL) _ca_function_fx(res2, CA_Cos, t, ctx); } else { ca_neg(t, t, ctx); if (res1 != NULL) _ca_function_fx(res1, CA_Sin, t, ctx); if (res2 != NULL) _ca_function_fx(res2, CA_Cos, t, ctx); if (res1 != NULL) ca_neg(res1, res1, ctx); } } } else { if (res1 != NULL) _ca_function_fx(res1, CA_Sin, x, ctx); if (res2 != NULL) _ca_function_fx(res2, CA_Cos, x, ctx); } ca_clear(pi, ctx); ca_clear(t, ctx); fmpq_clear(v); } #if 0 void ca_sin_cos_direct_exp_hack(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx) { ca_t i, ix, exp, sin, cos, t, u; ca_init(i, ctx); ca_init(ix, ctx); ca_init(exp, ctx); ca_init(sin, ctx); ca_init(cos, ctx); ca_init(t, ctx); ca_init(u, ctx); ca_i(i, ctx); ca_mul(ix, i, x, ctx); _ca_function_fx(sin, CA_Sin, x, ctx); _ca_function_fx(cos, CA_Cos, x, ctx); _ca_function_fx(exp, CA_Exp, ix, ctx); /* todo: create field in one step! */ ca_merge_fields(t, u, sin, exp, ctx); ca_swap(sin, t, ctx); ca_merge_fields(t, u, sin, i, ctx); ca_swap(sin, t, ctx); ca_merge_fields(t, u, sin, cos, ctx); ca_swap(sin, t, ctx); ca_swap(cos, u, ctx); if (res1 != NULL) ca_swap(res1, sin, ctx); if (res2 != NULL) ca_swap(res2, cos, ctx); ca_clear(i, ctx); ca_clear(ix, ctx); ca_clear(exp, ctx); ca_clear(sin, ctx); ca_clear(cos, ctx); ca_clear(t, ctx); ca_clear(u, ctx); } #endif void ca_sin_cos_tangent(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx) { ca_t t, u, v; if (CA_IS_SPECIAL(x)) { ca_sin_cos_special(res1, res2, x, ctx); return; } ca_init(t, ctx); ca_init(u, ctx); ca_init(v, ctx); ca_div_ui(t, x, 2, ctx); ca_tan_direct(t, t, ctx); if (CA_IS_SPECIAL(t)) { ca_sin_cos_direct(res1, res2, x, ctx); } else { ca_sqr(u, t, ctx); ca_add_ui(v, u, 1, ctx); ca_inv(v, v, ctx); if (res1 != NULL) { ca_mul(res1, t, v, ctx); ca_mul_ui(res1, res1, 2, ctx); } if (res2 != NULL) { ca_ui_sub(u, 1, u, ctx); ca_mul(res2, u, v, ctx); } } ca_clear(t, ctx); ca_clear(u, ctx); ca_clear(v, ctx); } void ca_sin_cos(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { ca_sin_cos_special(res1, res2, x, ctx); return; } if (CA_IS_QQ(x, ctx) && fmpq_is_zero(CA_FMPQ(x))) { if (res1 != NULL) ca_zero(res1, ctx); if (res2 != NULL) ca_one(res2, ctx); return; } if (ctx->options[CA_OPT_TRIG_FORM] == CA_TRIG_EXPONENTIAL) { ca_sin_cos_exponential(res1, res2, x, ctx); return; } if (ctx->options[CA_OPT_TRIG_FORM] == CA_TRIG_TANGENT) { ca_sin_cos_tangent(res1, res2, x, ctx); return; } ca_sin_cos_direct(res1, res2, x, ctx); } void ca_sin(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_sin_cos(res, NULL, x, ctx); } void ca_cos(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_sin_cos(NULL, res, x, ctx); } void ca_tan_special(ca_t res, const ca_t x, ca_ctx_t ctx) { if (ca_check_is_signed_inf(x, ctx) == T_TRUE) { ca_t s; ca_init(s, ctx); ca_sgn(s, x, ctx); ca_im(s, s, ctx); ca_sgn(s, s, ctx); if (ca_check_is_one(s, ctx) == T_TRUE) { ca_i(res, ctx); } else if (ca_check_is_neg_one(s, ctx) == T_TRUE) { ca_neg_i(res, ctx); } else if (ca_check_is_zero(s, ctx) == T_TRUE) { ca_undefined(res, ctx); } else { ca_unknown(res, ctx); } ca_clear(s, ctx); return; } if (ca_is_unknown(res, ctx)) ca_unknown(res, ctx); else ca_undefined(res, ctx); } void ca_tan_direct(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t t, u; truth_t pole; if (CA_IS_SPECIAL(x)) { ca_tan_special(res, x, ctx); return; } ca_init(t, ctx); ca_init(u, ctx); ca_pi(t, ctx); ca_div(t, x, t, ctx); if (ca_check_is_integer(t, ctx) == T_TRUE) { ca_zero(res, ctx); } else { ca_set_d(u, 0.5, ctx); ca_add(u, u, t, ctx); pole = ca_check_is_integer(u, ctx); if (pole == T_TRUE) { ca_uinf(res, ctx); } else if (pole == T_UNKNOWN) { ca_unknown(res, ctx); } else { fmpq_t v; fmpq_init(v); /* For now, only convert trivial values */ if (ca_get_fmpq(v, t, ctx) && (fmpz_equal_ui(fmpq_denref(v), 3) || fmpz_equal_ui(fmpq_denref(v), 4) || fmpz_equal_ui(fmpq_denref(v), 6) || fmpz_equal_ui(fmpq_denref(v), 8) || fmpz_equal_ui(fmpq_denref(v), 12))) { slong p, q; qqbar_t a; q = fmpz_get_ui(fmpq_denref(v)); p = fmpz_fdiv_ui(fmpq_numref(v), q); qqbar_init(a); qqbar_tan_pi(a, p, q); ca_set_qqbar(res, a, ctx); qqbar_clear(a); } else { /* todo: sign symmetry, ... */ _ca_function_fx(res, CA_Tan, x, ctx); } fmpq_clear(v); } } ca_clear(t, ctx); ca_clear(u, ctx); } void ca_tan_exponential(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { ca_tan_special(res, x, ctx); } else { ca_t s, c; ca_init(s, ctx); ca_init(c, ctx); ca_sin_cos_exponential(s, c, x, ctx); ca_div(res, s, c, ctx); ca_clear(s, ctx); ca_clear(c, ctx); return; } } void ca_tan_sine_cosine(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { ca_tan_special(res, x, ctx); } else { ca_t s, c; ca_init(s, ctx); ca_init(c, ctx); ca_sin_cos_direct(s, c, x, ctx); ca_div(res, s, c, ctx); ca_clear(s, ctx); ca_clear(c, ctx); return; } } void ca_tan(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { ca_tan_special(res, x, ctx); } else if (ctx->options[CA_OPT_TRIG_FORM] == CA_TRIG_EXPONENTIAL) { ca_tan_exponential(res, x, ctx); } else if (ctx->options[CA_OPT_TRIG_FORM] == CA_TRIG_SINE_COSINE) { ca_tan_sine_cosine(res, x, ctx); } else { ca_tan_direct(res, x, ctx); } } void ca_cot(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_tan(res, x, ctx); ca_inv(res, res, ctx); } calcium-0.4.1/ca/sqrt.c000066400000000000000000000046001407704557200146640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_sqrt_inert(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { /* todo: could compute inert sign + sqrt for signed inf */ ca_sqrt(res, x, ctx); } else { _ca_function_fx(res, CA_Sqrt, x, ctx); } } void _ca_sqrt_nofactor(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t y, tmp; ca_init(y, ctx); ca_init(tmp, ctx); _ca_function_fx(y, CA_Sqrt, x, ctx); ca_merge_fields(tmp, res, x, y, ctx); ca_clear(y, ctx); ca_clear(tmp, ctx); } void ca_sqrt_nofactor(ca_t res, const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (CA_IS_SIGNED_INF(x)) { ca_sgn(res, x, ctx); ca_sqrt(res, res, ctx); if (!ca_is_unknown(res, ctx)) res->field |= CA_INF; } else { ca_set(res, x, ctx); } } else { qqbar_t t; slong deg; qqbar_init(t); if (ca_get_qqbar(t, x, ctx)) { deg = qqbar_degree(t); qqbar_sqrt(t, t); /* use? qqbar_within_limits(t, ctx->options[CA_OPT_QQBAR_DEG_LIMIT], 0) */ if (qqbar_degree(t) <= FLINT_MAX(2, deg)) ca_set_qqbar(res, t, ctx); else _ca_sqrt_nofactor(res, x, ctx); } else { if (ca_check_is_negative_real(x, ctx) == T_TRUE) { ca_t i; ca_init(i, ctx); ca_i(i, ctx); ca_neg(res, x, ctx); _ca_sqrt_nofactor(res, res, ctx); ca_mul(res, res, i, ctx); ca_clear(i, ctx); } else { _ca_sqrt_nofactor(res, x, ctx); } } qqbar_clear(t); } } void ca_sqrt(ca_t res, const ca_t x, ca_ctx_t ctx) { #if 0 ca_sqrt_nofactor(res, x, ctx); #else ca_sqrt_factor(res, x, CA_FACTOR_POLY_SQF | CA_FACTOR_ZZ_SMOOTH, ctx); #endif } calcium-0.4.1/ca/sqrt_factor.c000066400000000000000000000125421407704557200162260ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_sqrt_factor(ca_t res, const ca_t x, ulong flags, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) { if (CA_IS_SIGNED_INF(x)) { ca_sgn(res, x, ctx); ca_sqrt_factor(res, res, flags, ctx); if (!ca_is_unknown(res, ctx)) res->field |= CA_INF; } else { ca_set(res, x, ctx); } } else { slong i; ca_factor_t fac; ca_t A, B, t; if (CA_IS_QQ(x, ctx)) { qqbar_t t; qqbar_init(t); qqbar_fmpq_root_ui(t, CA_FMPQ(x), 2); ca_set_qqbar(res, t, ctx); qqbar_clear(t); return; } ca_factor_init(fac, ctx); ca_init(A, ctx); ca_init(B, ctx); ca_init(t, ctx); ca_factor(fac, x, flags, ctx); ca_one(A, ctx); ca_one(B, ctx); for (i = 0; i < fac->length; i++) { if (CA_IS_QQ(fac->exp + i, ctx) && fmpz_is_one(CA_FMPQ_DENREF(fac->exp + i))) { if (!fmpz_is_zero(CA_FMPQ_DENREF(fac->exp + i))) { fmpz_t e; ca_ext_ptr ext; ext = ca_is_gen_as_ext(fac->base + i, ctx); if (ext != NULL && CA_EXT_HEAD(ext) == CA_Exp) { /* sqrt(exp(a)^n) = +/- exp(a*n/2) */ ca_mul_fmpz(t, CA_EXT_FUNC_ARGS(ext), CA_FMPQ_NUMREF(fac->exp + i), ctx); ca_div_ui(t, t, 2, ctx); ca_exp(t, t, ctx); ca_mul(A, A, t, ctx); continue; } /* todo: assert a != 0? */ if (ext != NULL && CA_EXT_HEAD(ext) == CA_Sqrt) { /* sqrt(sqrt(a)^n) = +/- a^(n/4) */ ca_set_fmpz(t, CA_FMPQ_NUMREF(fac->exp + i), ctx); ca_div_ui(t, t, 4, ctx); ca_pow(t, CA_EXT_FUNC_ARGS(ext), t, ctx); ca_mul(A, A, t, ctx); continue; } /* todo: assert a != 0? */ if (ext != NULL && CA_EXT_HEAD(ext) == CA_Pow) { /* sqrt((a^b)^n) = +/- a^(n*b/2) */ ca_mul_fmpz(t, CA_EXT_FUNC_ARGS(ext) + 1, CA_FMPQ_NUMREF(fac->exp + i), ctx); ca_div_ui(t, t, 2, ctx); ca_pow(t, CA_EXT_FUNC_ARGS(ext), t, ctx); ca_mul(A, A, t, ctx); continue; } fmpz_init(e); if (fmpz_is_odd(CA_FMPQ_NUMREF(fac->exp + i))) ca_mul(B, B, fac->base + i, ctx); fmpz_fdiv_q_2exp(e, CA_FMPQ_NUMREF(fac->exp + i), 1); ca_pow_fmpz(t, fac->base + i, e, ctx); ca_mul(A, A, t, ctx); fmpz_clear(e); } } else { ca_pow(t, fac->base + i, fac->exp + i, ctx); ca_mul(B, B, t, ctx); } } /* printf("factors:\n"); ca_factor_print(fac, ctx); printf("\n"); ca_print(A, ctx); printf("\n"); ca_print(B, ctx); printf("\n"); */ ca_sqrt_nofactor(B, B, ctx); ca_mul(A, A, B, ctx); /* check sign (todo: much improvable) */ { acb_t sA, sA2, sB; int success; slong prec, prec_limit, low_prec; low_prec = ctx->options[CA_OPT_LOW_PREC]; prec_limit = ctx->options[CA_OPT_PREC_LIMIT]; prec_limit = FLINT_MAX(prec_limit, low_prec); ca_sqrt_inert(B, x, ctx); acb_init(sA); acb_init(sA2); acb_init(sB); success = 0; for (prec = low_prec; prec <= prec_limit; prec *= 2) { ca_get_acb_raw(sA, A, prec, ctx); ca_get_acb_raw(sB, B, prec, ctx); acb_neg(sA2, sA); if (acb_overlaps(sA, sB) && !acb_overlaps(sA2, sB)) { ca_set(res, A, ctx); success = 1; break; } if (acb_overlaps(sA2, sB) && !acb_overlaps(sA, sB)) { ca_neg(res, A, ctx); success = 1; break; } } if (!success) { if (ca_check_is_zero(A, ctx) == T_TRUE) ca_zero(res, ctx); else ca_set(res, B, ctx); } acb_clear(sA); acb_clear(sA2); acb_clear(sB); } ca_factor_clear(fac, ctx); ca_clear(A, ctx); ca_clear(B, ctx); ca_clear(t, ctx); } } calcium-0.4.1/ca/swap.c000066400000000000000000000007761407704557200146570ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_swap(ca_t x, ca_t y, ca_ctx_t ctx) { ca_t tmp; *tmp = *x; *x = *y; *y = *tmp; } calcium-0.4.1/ca/test/000077500000000000000000000000001407704557200145065ustar00rootroot00000000000000calcium-0.4.1/ca/test/t-acos.c000066400000000000000000000046401407704557200160440ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("acos..."); fflush(stdout); flint_randinit(state); { ca_ctx_t ctx; ca_ctx_init(ctx); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { ca_t x, t1, t2, t3; if (n_randint(state, 10) == 0) { ca_ctx_clear(ctx); ca_ctx_init(ctx); } ca_init(x, ctx); ca_init(t1, ctx); ca_init(t2, ctx); ca_init(t3, ctx); ca_randtest_special(x, state, 5, 5, ctx); ca_acos_direct(t1, x, ctx); ca_acos_logarithm(t2, x, ctx); if (ca_check_equal(t1, t2, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("t1 = "); ca_print(t1, ctx); flint_printf("\n\n"); flint_printf("t2 = "); ca_print(t2, ctx); flint_printf("\n\n"); flint_abort(); } if (n_randint(state, 2)) ca_cos(t3, t2, ctx); else ca_cos(t3, t1, ctx); if (ca_check_is_infinity(t3, ctx) != T_TRUE && ca_check_is_undefined(t3, ctx) != T_TRUE) { if (ca_check_equal(t3, x, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("t2 = "); ca_print(t2, ctx); flint_printf("\n\n"); flint_printf("t3 = "); ca_print(t3, ctx); flint_printf("\n\n"); flint_abort(); } } ca_clear(x, ctx); ca_clear(t1, ctx); ca_clear(t2, ctx); ca_clear(t3, ctx); } ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-add.c000066400000000000000000000063311407704557200156460ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("add...."); fflush(stdout); flint_randinit(state); /* check special values */ { ca_ctx_t ctx; ca_t x, y, z; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_set_si(x, 2, ctx); ca_uinf(y, ctx); ca_add(z, x, y, ctx); if (ca_check_is_uinf(z, ctx) != T_TRUE) { flint_printf("FAIL: 2 + uinf\n"); flint_abort(); } ca_pos_inf(x, ctx); ca_uinf(y, ctx); ca_add(z, x, y, ctx); if (ca_check_is_undefined(z, ctx) != T_TRUE) { flint_printf("FAIL: +inf + uinf\n"); flint_abort(); } ca_neg_inf(x, ctx); ca_neg_inf(y, ctx); ca_add(z, x, y, ctx); if (ca_check_is_neg_inf(z, ctx) != T_TRUE) { flint_printf("FAIL: -inf + (-inf)\n"); flint_abort(); } ca_pos_inf(x, ctx); ca_neg_inf(y, ctx); ca_add(z, x, y, ctx); if (ca_check_is_undefined(z, ctx) != T_TRUE) { flint_printf("FAIL: +inf + (-inf)\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_ctx_clear(ctx); } for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, z, a, b; truth_t equal; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_init(a, ctx); ca_init(b, ctx); /* test (x + y) + z = x + (y + z) */ ca_randtest_special(x, state, 5, 5, ctx); ca_randtest_special(y, state, 5, 5, ctx); ca_randtest_special(z, state, 5, 5, ctx); ca_randtest_special(a, state, 5, 5, ctx); ca_randtest_special(b, state, 5, 5, ctx); ca_add(a, x, y, ctx); ca_add(a, a, z, ctx); ca_add(b, y, z, ctx); ca_add(b, x, b, ctx); equal = ca_check_equal(a, b, ctx); if (equal == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_printf("a = "); ca_print(a, ctx); flint_printf("\n\n"); flint_printf("b = "); ca_print(b, ctx); flint_printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_clear(a, ctx); ca_clear(b, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-asin.c000066400000000000000000000046401407704557200160510ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("asin..."); fflush(stdout); flint_randinit(state); { ca_ctx_t ctx; ca_ctx_init(ctx); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { ca_t x, t1, t2, t3; if (n_randint(state, 10) == 0) { ca_ctx_clear(ctx); ca_ctx_init(ctx); } ca_init(x, ctx); ca_init(t1, ctx); ca_init(t2, ctx); ca_init(t3, ctx); ca_randtest_special(x, state, 5, 5, ctx); ca_asin_direct(t1, x, ctx); ca_asin_logarithm(t2, x, ctx); if (ca_check_equal(t1, t2, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("t1 = "); ca_print(t1, ctx); flint_printf("\n\n"); flint_printf("t2 = "); ca_print(t2, ctx); flint_printf("\n\n"); flint_abort(); } if (n_randint(state, 2)) ca_sin(t3, t2, ctx); else ca_sin(t3, t1, ctx); if (ca_check_is_infinity(t3, ctx) != T_TRUE && ca_check_is_undefined(t3, ctx) != T_TRUE) { if (ca_check_equal(t3, x, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("t2 = "); ca_print(t2, ctx); flint_printf("\n\n"); flint_printf("t3 = "); ca_print(t3, ctx); flint_printf("\n\n"); flint_abort(); } } ca_clear(x, ctx); ca_clear(t1, ctx); ca_clear(t2, ctx); ca_clear(t3, ctx); } ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-atan.c000066400000000000000000000046341407704557200160450ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("atan..."); fflush(stdout); flint_randinit(state); { ca_ctx_t ctx; ca_ctx_init(ctx); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { ca_t x, t1, t2, t3; if (n_randint(state, 10) == 0) { ca_ctx_clear(ctx); ca_ctx_init(ctx); } ca_init(x, ctx); ca_init(t1, ctx); ca_init(t2, ctx); ca_init(t3, ctx); ca_randtest_special(x, state, 5, 5, ctx); ca_atan_direct(t1, x, ctx); ca_atan_logarithm(t2, x, ctx); if (ca_check_equal(t1, t2, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("t1 = "); ca_print(t1, ctx); flint_printf("\n\n"); flint_printf("t2 = "); ca_print(t2, ctx); flint_printf("\n\n"); flint_abort(); } if (n_randint(state, 2)) ca_tan(t3, t2, ctx); else ca_tan(t3, t1, ctx); if (ca_check_is_uinf(t3, ctx) != T_TRUE && ca_check_is_undefined(t3, ctx) != T_TRUE) { if (ca_check_equal(t3, x, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("t2 = "); ca_print(t2, ctx); flint_printf("\n\n"); flint_printf("t3 = "); ca_print(t3, ctx); flint_printf("\n\n"); flint_abort(); } } ca_clear(x, ctx); ca_clear(t1, ctx); ca_clear(t2, ctx); ca_clear(t3, ctx); } ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-conj.c000066400000000000000000000035001407704557200160420ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("conj...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, z; truth_t equal; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_randtest_special(x, state, 5, 5, ctx); switch (n_randint(state, 3)) { case 0: ca_conj(y, x, ctx); break; case 1: ca_conj_deep(y, x, ctx); break; case 2: ca_conj_shallow(y, x, ctx); break; } switch (n_randint(state, 3)) { case 0: ca_conj(z, y, ctx); break; case 1: ca_conj_deep(z, y, ctx); break; case 2: ca_conj_shallow(z, y, ctx); break; } equal = ca_check_equal(x, z, ctx); if (equal == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-ctx_init_clear.c000066400000000000000000000012751407704557200201070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { flint_rand_t state; ca_ctx_t ctx; flint_printf("ctx_init_clear...."); fflush(stdout); flint_randinit(state); ca_ctx_init(ctx); ca_ctx_clear(ctx); flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-div.c000066400000000000000000000133061407704557200157000ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("div...."); fflush(stdout); flint_randinit(state); /* check special values */ { ca_ctx_t ctx; ca_t x, y, z; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_set_si(x, 2, ctx); ca_uinf(y, ctx); ca_div(z, x, y, ctx); if (ca_check_is_zero(z, ctx) != T_TRUE) { flint_printf("FAIL: 2 / uinf\n"); flint_abort(); } ca_div(z, y, x, ctx); if (ca_check_is_uinf(z, ctx) != T_TRUE) { flint_printf("FAIL: uinf / 2\n"); flint_abort(); } ca_zero(x, ctx); ca_uinf(y, ctx); ca_div(z, x, y, ctx); if (ca_check_is_zero(z, ctx) != T_TRUE) { flint_printf("FAIL: 0 / uinf\n"); flint_abort(); } ca_div(z, y, x, ctx); if (ca_check_is_uinf(z, ctx) != T_TRUE) { flint_printf("FAIL: uinf / 0\n"); flint_abort(); } ca_zero(x, ctx); ca_pos_inf(y, ctx); ca_div(z, x, y, ctx); if (ca_check_is_zero(z, ctx) != T_TRUE) { flint_printf("FAIL: 0 / +inf\n"); flint_abort(); } ca_div(z, y, x, ctx); if (ca_check_is_uinf(z, ctx) != T_TRUE) { flint_printf("FAIL: +inf / 0\n"); flint_abort(); } ca_set_si(x, -2, ctx); ca_pos_inf(y, ctx); ca_div(z, x, y, ctx); if (ca_check_is_zero(z, ctx) != T_TRUE) { flint_printf("FAIL: -2 / +inf\n"); flint_abort(); } ca_div(z, y, x, ctx); if (ca_check_is_neg_inf(z, ctx) != T_TRUE) { flint_printf("FAIL: +inf / -2\n"); flint_abort(); } ca_pos_inf(x, ctx); ca_uinf(y, ctx); ca_div(z, x, y, ctx); if (ca_check_is_undefined(z, ctx) != T_TRUE) { flint_printf("FAIL: +inf / uinf\n"); flint_abort(); } ca_div(z, y, x, ctx); if (ca_check_is_undefined(z, ctx) != T_TRUE) { flint_printf("FAIL: uinf / +uinf\n"); flint_abort(); } ca_one(x, ctx); ca_zero(y, ctx); ca_div(z, x, y, ctx); if (ca_check_is_uinf(z, ctx) != T_TRUE) { flint_printf("FAIL: 1 / 0\n"); flint_abort(); } ca_zero(x, ctx); ca_zero(y, ctx); ca_div(z, x, y, ctx); if (ca_check_is_undefined(z, ctx) != T_TRUE) { flint_printf("FAIL: 0 / 0\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_ctx_clear(ctx); } for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, z, a, b, c; truth_t equal; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_init(a, ctx); ca_init(b, ctx); ca_init(c, ctx); /* test (x / y) / z = x / (y * z) */ ca_randtest_special(x, state, 5, 5, ctx); ca_randtest_special(y, state, 5, 5, ctx); ca_randtest_special(z, state, 5, 5, ctx); ca_randtest_special(a, state, 5, 5, ctx); ca_randtest_special(b, state, 5, 5, ctx); ca_div(a, x, y, ctx); ca_div(a, a, z, ctx); ca_mul(b, y, z, ctx); ca_div(b, x, b, ctx); equal = ca_check_equal(a, b, ctx); if (equal == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_printf("a = "); ca_print(a, ctx); flint_printf("\n\n"); flint_printf("b = "); ca_print(b, ctx); flint_printf("\n\n"); flint_abort(); } /* test (y + z) / x = y / x + z / x */ ca_add(a, y, z, ctx); ca_div(a, a, x, ctx); ca_div(b, y, x, ctx); ca_div(c, z, x, ctx); ca_add(b, b, c, ctx); equal = ca_check_equal(a, b, ctx); if (equal == T_FALSE) { if (!(ca_check_is_zero(x, ctx) == T_TRUE || ca_check_is_infinity(y, ctx) == T_TRUE || ca_check_is_infinity(z, ctx) == T_TRUE)) { flint_printf("FAIL (distributivity)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_printf("a = "); ca_print(a, ctx); flint_printf("\n\n"); flint_printf("b = "); ca_print(b, ctx); flint_printf("\n\n"); flint_abort(); } } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_clear(a, ctx); ca_clear(b, ctx); ca_clear(c, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-erf.c000066400000000000000000000126661407704557200157020ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_randtest_zero(ca_t x, flint_rand_t state, ca_ctx_t ctx) { if (n_randint(state, 2)) { ca_zero(x, ctx); } else { ca_t t; ca_init(t, ctx); ca_sqrt_ui(x, 6, ctx); ca_mul_ui(x, x, 2, ctx); ca_add_ui(x, x, 5, ctx); ca_sqrt(x, x, ctx); ca_sqrt_ui(t, 2, ctx); ca_sub(x, x, t, ctx); ca_sqrt_ui(t, 3, ctx); ca_sub(x, x, t, ctx); ca_clear(t, ctx); } } int main() { slong iter; flint_rand_t state; flint_printf("erf...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, v, s; acb_t ax, ay, as, as2; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(v, ctx); ca_init(s, ctx); acb_init(ax); acb_init(ay); acb_init(as); acb_init(as2); ca_randtest(x, state, 3, 5, ctx); ca_randtest_zero(v, state, ctx); ca_add(y, x, v, ctx); switch (n_randint(state, 4)) { case 0: ca_neg(y, y, ctx); break; case 1: ca_i(s, ctx); ca_mul(y, y, s, ctx); break; case 2: ca_neg_i(s, ctx); ca_mul(y, y, s, ctx); break; } switch (n_randint(state, 3)) { case 0: ca_erf(x, x, ctx); break; case 1: ca_erfc(x, x, ctx); break; default: ca_erfi(x, x, ctx); break; } switch (n_randint(state, 3)) { case 0: ca_erf(y, y, ctx); break; case 1: ca_erfc(y, y, ctx); break; default: ca_erfi(y, y, ctx); break; } if (n_randint(state, 2)) ca_sqr(x, x, ctx); switch (n_randint(state, 4)) { case 0: ca_neg(x, x, ctx); break; case 1: ca_i(s, ctx); ca_mul(x, x, s, ctx); break; case 2: ca_neg_i(s, ctx); ca_mul(x, x, s, ctx); break; } if (n_randint(state, 2)) ca_sqr(y, y, ctx); switch (n_randint(state, 4)) { case 0: ca_neg(y, y, ctx); break; case 1: ca_i(s, ctx); ca_mul(y, y, s, ctx); break; case 2: ca_neg_i(s, ctx); ca_mul(y, y, s, ctx); break; } ca_add(s, x, y, ctx); ca_get_acb(ax, x, 53, ctx); ca_get_acb(ay, y, 53, ctx); ca_get_acb(as, s, 53, ctx); acb_add(as2, ax, ay, 53); if (!acb_overlaps(as, as2)) { flint_printf("FAIL\n"); flint_printf("x = "); ca_print(x, ctx); printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); printf("\n\n"); flint_printf("s = "); ca_print(s, ctx); printf("\n\n"); flint_abort(); } acb_clear(ax); acb_clear(ay); acb_clear(as); acb_clear(as2); ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(v, ctx); ca_clear(s, ctx); ca_ctx_clear(ctx); } { ca_ctx_t ctx; ca_t x, y; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); /* Erf(2*Log(Sqrt(1/2-Sqrt(2)/4))+Log(4)) - Erf(Log(2-Sqrt(2))) */ ca_sqrt_ui(x, 2, ctx); ca_div_ui(x, x, 4, ctx); ca_one(y, ctx); ca_div_ui(y, y, 2, ctx); ca_sub(x, y, x, ctx); ca_sqrt(x, x, ctx); ca_log(x, x, ctx); ca_mul_ui(x, x, 2, ctx); ca_set_ui(y, 4, ctx); ca_log(y, y, ctx); ca_add(x, y, x, ctx); ca_erf(x, x, ctx); ca_sqrt_ui(y, 2, ctx); ca_ui_sub(y, 2, y, ctx); ca_log(y, y, ctx); ca_erf(y, y, ctx); ca_sub(x, x, y, ctx); if (ca_check_is_zero(x, ctx) != T_TRUE) { flint_printf("FAIL (example 1)\n"); flint_printf("x = "); ca_print(x, ctx); printf("\n\n"); flint_abort(); } /* Erf(Sqrt(2))^2 + Erfi(Sqrt(-2))^2 */ ca_sqrt_ui(x, 2, ctx); ca_erf(x, x, ctx); ca_pow_ui(x, x, 2, ctx); ca_set_si(y, -2, ctx); ca_sqrt(y, y, ctx); ca_erfi(y, y, ctx); ca_pow_ui(y, y, 2, ctx); ca_add(x, x, y, ctx); if (ca_check_is_zero(x, ctx) != T_TRUE) { flint_printf("FAIL (example 2)\n"); flint_printf("x = "); ca_print(x, ctx); printf("\n\n"); flint_abort(); } /* Erf(Sqrt(2))^4 - Erfi(Sqrt(-2))^4 */ ca_sqrt_ui(x, 2, ctx); ca_erf(x, x, ctx); ca_pow_ui(x, x, 4, ctx); ca_set_si(y, -2, ctx); ca_sqrt(y, y, ctx); ca_erfi(y, y, ctx); ca_pow_ui(y, y, 4, ctx); ca_sub(x, x, y, ctx); if (ca_check_is_zero(x, ctx) != T_TRUE) { flint_printf("FAIL (example 3)\n"); flint_printf("x = "); ca_print(x, ctx); printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-exp.c000066400000000000000000000055451407704557200157200ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("exp...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, z, a, b, c, d, e; truth_t equal; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_init(a, ctx); ca_init(b, ctx); ca_init(c, ctx); ca_init(d, ctx); ca_init(e, ctx); /* exp(x+y+z) = exp(x)*exp(y)*exp(z) */ ca_randtest(x, state, 5, 5, ctx); ca_randtest(y, state, 5, 5, ctx); ca_randtest(z, state, 5, 5, ctx); if (n_randint(state, 4) == 0) { if (n_randint(state, 2)) { do { ca_randtest(a, state, 5, 5, ctx); ca_log(a, a, ctx); } while (ca_check_is_number(a, ctx) != T_TRUE); ca_mul(x, x, a, ctx); } else { ca_pi_i(a, ctx); ca_mul(x, x, a, ctx); } } ca_exp(a, x, ctx); ca_exp(b, y, ctx); ca_exp(c, z, ctx); ca_add(d, x, y, ctx); ca_add(d, d, z, ctx); ca_exp(d, d, ctx); ca_mul(e, a, b, ctx); ca_mul(e, e, c, ctx); equal = ca_check_equal(d, e, ctx); if (equal == T_FALSE) { flint_printf("FAIL exp(x+y+z) = exp(x)*exp(y)*exp(z)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_printf("a = "); ca_print(a, ctx); flint_printf("\n\n"); flint_printf("b = "); ca_print(b, ctx); flint_printf("\n\n"); flint_printf("c = "); ca_print(c, ctx); flint_printf("\n\n"); flint_printf("d = "); ca_print(d, ctx); flint_printf("\n\n"); flint_printf("e = "); ca_print(e, ctx); flint_printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_clear(a, ctx); ca_clear(b, ctx); ca_clear(c, ctx); ca_clear(d, ctx); ca_clear(e, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-field_init_clear.c000066400000000000000000000024071407704557200203720ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" int main() { flint_rand_t state; flint_printf("field_init_clear...."); fflush(stdout); flint_randinit(state); { ca_ctx_t ctx; ca_field_t K; ca_field_t I, Pi; qqbar_t t; qqbar_init(t); qqbar_i(t); ca_ctx_init(ctx); ca_field_init_nf(I, t, ctx); ca_field_init_const(Pi, CA_Pi, ctx); ca_field_init_multi(K, 2, ctx); /* ca_field_set_ext(K, 0, I); ca_field_set_ext(K, 1, Pi); flint_printf("\n"); ca_field_print(K); flint_printf("\n"); */ ca_field_clear(I, ctx); ca_field_clear(Pi, ctx); ca_field_clear(K, ctx); ca_ctx_clear(ctx); qqbar_clear(t); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-fmpz_mpoly_evaluate.c000066400000000000000000000057031407704557200212020ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_vec.h" int main() { slong iter; flint_rand_t state; flint_printf("fmpz_mpoly_evaluate...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t cactx; slong i, n; fmpz_mpoly_ctx_t ctx; fmpz_mpoly_t f, g, h; ca_ptr x; ca_t fx, gx, hx, y; ca_ctx_init(cactx); n = 1 + n_randint(state, 5); fmpz_mpoly_ctx_init(ctx, n, ORD_LEX); fmpz_mpoly_init(f, ctx); fmpz_mpoly_init(g, ctx); fmpz_mpoly_init(h, ctx); x = _ca_vec_init(n, cactx); ca_init(fx, cactx); ca_init(gx, cactx); ca_init(hx, cactx); ca_init(y, cactx); for (i = 0; i < n; i++) ca_randtest(x + i, state, 5, 5, cactx); fmpz_mpoly_randtest_bound(f, state, 1 + n_randint(state, 30), 10, 1 + n_randint(state, 4), ctx); fmpz_mpoly_randtest_bound(g, state, 1 + n_randint(state, 30), 10, 1 + n_randint(state, 4), ctx); fmpz_mpoly_add(h, f, g, ctx); ca_fmpz_mpoly_evaluate(fx, f, x, ctx, cactx); ca_fmpz_mpoly_evaluate(gx, g, x, ctx, cactx); ca_fmpz_mpoly_evaluate(hx, h, x, ctx, cactx); ca_add(y, fx, gx, cactx); if (ca_check_equal(y, hx, cactx) == T_FALSE) { flint_printf("FAIL!\n"); flint_printf("f = "); fmpz_mpoly_print_pretty(f, NULL, ctx); flint_printf("\n\n"); flint_printf("g = "); fmpz_mpoly_print_pretty(g, NULL, ctx); flint_printf("\n\n"); flint_printf("h = "); fmpz_mpoly_print_pretty(h, NULL, ctx); flint_printf("\n\n"); for (i = 0; i < n; i++) { flint_printf("x%wd = ", i + 1); ca_print(x + i, cactx); flint_printf("\n\n"); } flint_printf("fx = "); ca_print(fx, cactx); flint_printf("\n\n"); flint_printf("gx = "); ca_print(gx, cactx); flint_printf("\n\n"); flint_printf("hx = "); ca_print(hx, cactx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, cactx); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_clear(f, ctx); fmpz_mpoly_clear(g, ctx); fmpz_mpoly_clear(h, ctx); fmpz_mpoly_ctx_clear(ctx); _ca_vec_clear(x, n, cactx); ca_clear(fx, cactx); ca_clear(gx, cactx); ca_clear(hx, cactx); ca_clear(y, cactx); ca_ctx_clear(cactx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-gamma.c000066400000000000000000000051071407704557200162000ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("gamma...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, gx, gy, gxgy; acb_t gax, gay, agx, agy, agxgy, gaxgay; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(gx, ctx); ca_init(gy, ctx); ca_init(gxgy, ctx); acb_init(gax); acb_init(gay); acb_init(agx); acb_init(agy); acb_init(agxgy); acb_init(gaxgay); ca_randtest(x, state, 3, 5, ctx); if (n_randint(state, 2)) ca_randtest(y, state, 3, 5, ctx); else ca_randtest_rational(y, state, 5, ctx); if (n_randint(state, 2)) ca_add(y, y, x, ctx); ca_gamma(gx, x, ctx); ca_gamma(gy, y, ctx); ca_add(gxgy, gx, gy, ctx); ca_get_acb(agx, gx, 53, ctx); ca_get_acb(agy, gy, 53, ctx); ca_get_acb(agxgy, gxgy, 53, ctx); ca_get_acb(gax, x, 53, ctx); acb_gamma(gax, gax, 53); ca_get_acb(gay, y, 53, ctx); acb_gamma(gay, gay, 53); acb_add(gaxgay, gax, gay, 53); if (!acb_overlaps(agx, gax) || !acb_overlaps(agy, gay) || !acb_overlaps(agxgy, gaxgay)) { flint_printf("FAIL\n"); flint_printf("x = "); ca_print(x, ctx); printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); printf("\n\n"); flint_printf("gx = "); ca_print(gx, ctx); printf("\n\n"); flint_printf("gy = "); ca_print(gy, ctx); printf("\n\n"); flint_printf("gxgy = "); ca_print(gxgy, ctx); printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(gx, ctx); ca_clear(gy, ctx); ca_clear(gxgy, ctx); acb_clear(gax); acb_clear(gay); acb_clear(agx); acb_clear(agy); acb_clear(agxgy); acb_clear(gaxgay); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-get_fexpr.c000066400000000000000000000054151407704557200171030ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("get_fexpr...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y; fexpr_t f; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); fexpr_init(f); ca_randtest_special(x, state, 5, 5, ctx); ca_get_fexpr(f, x, 0, ctx); if (!ca_set_fexpr(y, f, ctx)) { flint_printf("FAIL: unable to parse\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("f = "); fexpr_print(f); flint_printf("\n\n"); flint_abort(); } if (ca_check_equal(x, y, ctx) == T_FALSE) { flint_printf("FAIL: not equal!\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("f = "); fexpr_print(f); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_abort(); } if (ca_check_equal(x, y, ctx) == T_FALSE) { flint_printf("FAIL: not equal!\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("f = "); fexpr_print(f); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_abort(); } if (ca_check_equal(x, y, ctx) != T_TRUE && !ca_is_unknown(x, ctx)) { flint_printf("FAIL: not equal!\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("f = "); fexpr_print(f); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_abort(); } /* if (!ca_equal_repr(x, y, ctx)) { flint_printf("Warning: not equal repr!\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("f = "); fexpr_print(f); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); } */ fexpr_clear(f); ca_clear(x, ctx); ca_clear(y, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-get_str.c000066400000000000000000000021531407704557200165630ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("get_str..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x; char * s; slong slen; ca_ctx_init(ctx); ca_init(x, ctx); /* just check that it doesn't crash */ ca_randtest_special(x, state, 10, 100, ctx); s = ca_get_str(x, ctx); slen = strlen(s); slen = slen; flint_free(s); ca_clear(x, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-init_clear.c000066400000000000000000000016501407704557200172260ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { flint_rand_t state; flint_printf("init_clear...."); fflush(stdout); flint_randinit(state); { ca_ctx_t ctx; ca_t x; ca_ctx_init(ctx); ca_init(x, ctx); if (!fmpz_is_zero(CA_FMPQ_NUMREF(x))) flint_abort(); if (!fmpz_is_one(CA_FMPQ_DENREF(x))) flint_abort(); ca_clear(x, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-log.c000066400000000000000000000114121407704557200156730ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("log...."); fflush(stdout); flint_randinit(state); /* check numerical evaluation */ for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y; acb_t ax, ay, logax; slong prec; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); acb_init(ax); acb_init(ay); acb_init(logax); prec = 10 + n_randint(state, 100); ca_randtest(x, state, 5, 5, ctx); ca_randtest(y, state, 5, 5, ctx); if (n_randint(state, 2)) ca_exp(x, x, ctx); if (n_randint(state, 2)) ca_pow(x, x, y, ctx); ca_log(y, x, ctx); ca_get_acb(ax, x, prec, ctx); ca_get_acb(ay, y, prec, ctx); acb_log(logax, ax, prec); if (!acb_overlaps(logax, ay)) { flint_printf("FAIL (overlap)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("ax = "); acb_printn(ax, 30, ARB_STR_NO_RADIUS); flint_printf("\n\n"); flint_printf("ay = "); acb_printn(ay, 30, ARB_STR_NO_RADIUS); flint_printf("\n\n"); flint_printf("logax = "); acb_printn(logax, 30, ARB_STR_NO_RADIUS); flint_printf("\n\n"); flint_abort(); } acb_clear(ax); acb_clear(ay); acb_clear(logax); ca_clear(x, ctx); ca_clear(y, ctx); ca_ctx_clear(ctx); } for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, z, a, b, c, d, e, f; truth_t equal, zero; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_init(a, ctx); ca_init(b, ctx); ca_init(c, ctx); ca_init(d, ctx); ca_init(e, ctx); ca_init(f, ctx); /* log(x * y * z) - log(x) - log(y) - log(z) */ /* testing for positive x and y here -- need better test code for complex numbers */ ca_randtest(x, state, 5, 5, ctx); ca_randtest(y, state, 5, 5, ctx); ca_randtest(z, state, 5, 5, ctx); ca_abs(x, x, ctx); ca_abs(y, y, ctx); /* Test a bug */ if (iter == 0) { ca_sqrt_ui(x, 2, ctx); ca_div_ui(x, x, 3, ctx); ca_sqrt(x, x, ctx); ca_set_ui(y, 1, ctx); ca_div_ui(y, y, 2, ctx); ca_one(z, ctx); } /* a = log(x*y*z) */ ca_mul(a, x, y, ctx); ca_mul(a, a, z, ctx); ca_log(a, a, ctx); /* b = log(x), c = log(y), d = log(z) */ ca_log(b, x, ctx); ca_log(c, y, ctx); ca_log(d, z, ctx); /* e = log(x) + log(y) + log(c) */ ca_add(e, b, c, ctx); ca_add(e, e, d, ctx); ca_sub(f, a, e, ctx); equal = ca_check_equal(a, e, ctx); if (ca_check_is_infinity(a, ctx) == T_FALSE) { zero = ca_check_is_zero(f, ctx); } else { zero = T_UNKNOWN; } if (equal == T_FALSE || zero == T_FALSE) { flint_printf("FAIL (log(x * y * z) - log(x) - log(y) - log(z) != 0)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_printf("a = "); ca_print(a, ctx); flint_printf("\n\n"); flint_printf("b = "); ca_print(b, ctx); flint_printf("\n\n"); flint_printf("c = "); ca_print(c, ctx); flint_printf("\n\n"); flint_printf("d = "); ca_print(d, ctx); flint_printf("\n\n"); flint_printf("e = "); ca_print(e, ctx); flint_printf("\n\n"); flint_printf("f = "); ca_print(f, ctx); flint_printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_clear(a, ctx); ca_clear(b, ctx); ca_clear(c, ctx); ca_clear(d, ctx); ca_clear(e, ctx); ca_clear(f, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-log_identities.c000066400000000000000000000124341407704557200201210ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" /* atan(x) = -i/2 log((1+ix)/(1-ix)) */ /* valid for -inf < x < inf */ void simple_ca_atan(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t t, u, v; ca_init(t, ctx); ca_init(u, ctx); ca_init(v, ctx); ca_i(t, ctx); ca_mul(u, x, t, ctx); /* v = 1 + i x */ ca_add_ui(v, u, 1, ctx); /* res = 1 - i x */ ca_sub_ui(res, u, 1, ctx); ca_neg(res, res, ctx); ca_div(res, v, res, ctx); ca_log(res, res, ctx); ca_mul(res, res, t, ctx); ca_div_ui(res, res, 2, ctx); ca_neg(res, res, ctx); ca_clear(t, ctx); ca_clear(u, ctx); ca_clear(v, ctx); } void simple_ca_atan_p_q(ca_t res, ulong p, ulong q, ca_ctx_t ctx) { ca_set_ui(res, p, ctx); ca_div_ui(res, res, q, ctx); simple_ca_atan(res, res, ctx); } /* valid for -1 < x < 1 */ void simple_ca_atanh(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); ca_add_ui(t, x, 1, ctx); ca_sub_ui(u, x, 1, ctx); ca_neg(u, u, ctx); ca_div(res, t, u, ctx); ca_log(res, res, ctx); ca_div_ui(res, res, 2, ctx); ca_clear(t, ctx); ca_clear(u, ctx); } void simple_ca_atanh_p_q(ca_t res, ulong p, ulong q, ca_ctx_t ctx) { ca_set_ui(res, p, ctx); ca_div_ui(res, res, q, ctx); simple_ca_atanh(res, res, ctx); } #define NUM_FORMULAS 8 slong machin_formulas[NUM_FORMULAS][4][2] = { {{1, 1}, {0, 0}, {0, 0}, {0, 0}}, {{1, 2}, {1, 3}, {0, 0}, {0, 0}}, {{2, 2}, {-1, 7}, {0, 0}, {0, 0}}, {{2, 3}, {1, 7}, {0, 0}, {0, 0}}, {{4, 5}, {-1, 239}, {0, 0}, {0, 0}}, {{1, 2}, {1, 5}, {1, 8}, {0, 0}}, {{1, 3}, {1, 4}, {1, 7}, {1, 13}}, {{12, 49}, {32, 57}, {-5, 239}, {12, 110443}}, }; #define NUM_FORMULAS2 7 slong hyperbolic_logs[NUM_FORMULAS2] = {2, 3, 5, 2, 3, 5, 7}; slong hyperbolic_machin_formulas[NUM_FORMULAS2][4][2] = { {{14, 31}, {10, 49}, {6, 161}, {0, 0}}, {{22, 31}, {16, 49}, {10, 161}, {0, 0}}, {{32, 31}, {24, 49}, {14, 161}, {0, 0}}, {{144, 251}, {54, 449}, {-38, 4801}, {62, 8749}}, {{228, 251}, {86, 449}, {-60, 4801}, {98, 8749}}, {{334, 251}, {126, 449}, {-88, 4801}, {144, 8749}}, {{404, 251}, {152, 449}, {-106, 4801}, {174, 8749}}, }; int main() { slong iter; flint_rand_t state; flint_printf("log_identities...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1; iter++) { ca_ctx_t ctx; ca_t x, y, pi4; slong i, j, c, q; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(pi4, ctx); ca_pi(pi4, ctx); ca_div_ui(pi4, pi4, 4, ctx); for (i = 0; i < NUM_FORMULAS; i++) { ca_zero(x, ctx); for (j = 0; j < 4; j++) { c = machin_formulas[i][j][0]; q = machin_formulas[i][j][1]; if (c != 0) { simple_ca_atan_p_q(y, 1, q, ctx); ca_mul_si(y, y, c, ctx); ca_add(x, x, y, ctx); } } ca_sub(x, x, pi4, ctx); if (!(CA_IS_QQ(x, ctx) && fmpq_is_zero(CA_FMPQ(x)))) { flint_printf("FAIL\n\n"); for (j = 0; j < 4; j++) { c = machin_formulas[i][j][0]; q = machin_formulas[i][j][1]; flint_printf("%wd %wd ", c, q); } flint_printf("\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_abort(); } } for (i = 0; i < NUM_FORMULAS2; i++) { ca_zero(x, ctx); for (j = 0; j < 4; j++) { c = hyperbolic_machin_formulas[i][j][0]; q = hyperbolic_machin_formulas[i][j][1]; if (c != 0) { simple_ca_atanh_p_q(y, 1, q, ctx); ca_mul_si(y, y, c, ctx); ca_add(x, x, y, ctx); } } ca_set_ui(y, hyperbolic_logs[i], ctx); ca_log(y, y, ctx); ca_sub(x, x, y, ctx); if (!(CA_IS_QQ(x, ctx) && fmpq_is_zero(CA_FMPQ(x)))) { flint_printf("FAIL\n\n"); for (j = 0; j < 4; j++) { c = hyperbolic_machin_formulas[i][j][0]; q = hyperbolic_machin_formulas[i][j][1]; flint_printf("%wd %wd ", c, q); } flint_printf("\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_abort(); } } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(pi4, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-mul.c000066400000000000000000000106711407704557200157150ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("mul...."); fflush(stdout); flint_randinit(state); /* check special values */ { ca_ctx_t ctx; ca_t x, y, z; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_set_si(x, 2, ctx); ca_uinf(y, ctx); ca_mul(z, x, y, ctx); if (ca_check_is_uinf(z, ctx) != T_TRUE) { flint_printf("FAIL: 2 * uinf\n"); flint_abort(); } ca_zero(x, ctx); ca_uinf(y, ctx); ca_mul(z, x, y, ctx); if (ca_check_is_undefined(z, ctx) != T_TRUE) { flint_printf("FAIL: 0 * uinf\n"); flint_abort(); } ca_zero(x, ctx); ca_pos_inf(y, ctx); ca_mul(z, x, y, ctx); if (ca_check_is_undefined(z, ctx) != T_TRUE) { flint_printf("FAIL: 0 * +inf\n"); flint_abort(); } ca_set_si(x, -2, ctx); ca_pos_inf(y, ctx); ca_mul(z, x, y, ctx); if (ca_check_is_neg_inf(z, ctx) != T_TRUE) { flint_printf("FAIL: -2 * +inf\n"); flint_abort(); } ca_pos_inf(x, ctx); ca_uinf(y, ctx); ca_mul(z, x, y, ctx); if (ca_check_is_uinf(z, ctx) != T_TRUE) { flint_printf("FAIL: +inf * uinf\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_ctx_clear(ctx); } for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, z, a, b, c; truth_t equal; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_init(a, ctx); ca_init(b, ctx); ca_init(c, ctx); /* test (x * y) * z = x * (y * z) */ ca_randtest_special(x, state, 5, 5, ctx); ca_randtest_special(y, state, 5, 5, ctx); ca_randtest_special(z, state, 5, 5, ctx); ca_randtest_special(a, state, 5, 5, ctx); ca_randtest_special(b, state, 5, 5, ctx); ca_mul(a, x, y, ctx); ca_mul(a, a, z, ctx); ca_mul(b, y, z, ctx); ca_mul(b, x, b, ctx); equal = ca_check_equal(a, b, ctx); if (equal == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_printf("a = "); ca_print(a, ctx); flint_printf("\n\n"); flint_printf("b = "); ca_print(b, ctx); flint_printf("\n\n"); flint_abort(); } /* test x * (y + z) = x * y + x * z */ ca_add(a, y, z, ctx); ca_mul(a, x, a, ctx); ca_mul(b, x, y, ctx); ca_mul(c, x, z, ctx); ca_add(b, b, c, ctx); equal = ca_check_equal(a, b, ctx); if (equal == T_FALSE) { if (!(ca_check_is_infinity(x, ctx) == T_TRUE || ca_check_is_infinity(y, ctx) == T_TRUE || ca_check_is_infinity(z, ctx) == T_TRUE)) { flint_printf("FAIL (distributivity)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_printf("a = "); ca_print(a, ctx); flint_printf("\n\n"); flint_printf("b = "); ca_print(b, ctx); flint_printf("\n\n"); flint_abort(); } } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_clear(a, ctx); ca_clear(b, ctx); ca_clear(c, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-neg.c000066400000000000000000000066651407704557200157010ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { flint_rand_t state; flint_printf("neg...."); fflush(stdout); flint_randinit(state); { ca_ctx_t ctx; ca_t x, y, z; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_pos_inf(x, ctx); ca_neg(y, x, ctx); ca_set(z, x, ctx); ca_neg(z, z, ctx); if (ca_check_is_neg_inf(y, ctx) != T_TRUE || ca_check_is_neg_inf(z, ctx) != T_TRUE) { flint_printf("FAIL: pos_inf\n"); flint_abort(); } ca_neg_inf(x, ctx); ca_neg(y, x, ctx); ca_set(z, x, ctx); ca_neg(z, z, ctx); if (ca_check_is_pos_inf(y, ctx) != T_TRUE || ca_check_is_pos_inf(z, ctx) != T_TRUE) { flint_printf("FAIL: neg_inf\n"); flint_abort(); } ca_pos_i_inf(x, ctx); ca_neg(y, x, ctx); ca_set(z, x, ctx); ca_neg(z, z, ctx); if (ca_check_is_neg_i_inf(y, ctx) != T_TRUE || ca_check_is_neg_i_inf(z, ctx) != T_TRUE) { flint_printf("FAIL: pos_i_inf\n"); flint_abort(); } ca_undefined(x, ctx); ca_neg(y, x, ctx); ca_set(z, x, ctx); ca_neg(z, z, ctx); if (ca_check_is_undefined(y, ctx) != T_TRUE || ca_check_is_undefined(z, ctx) != T_TRUE) { flint_printf("FAIL: neg_i_inf\n"); flint_abort(); } ca_neg_i_inf(x, ctx); ca_neg(y, x, ctx); ca_set(z, x, ctx); ca_neg(z, z, ctx); if (ca_check_is_pos_i_inf(y, ctx) != T_TRUE || ca_check_is_pos_i_inf(z, ctx) != T_TRUE) { flint_printf("FAIL: neg_i_inf\n"); flint_abort(); } ca_uinf(x, ctx); ca_neg(y, x, ctx); ca_set(z, x, ctx); ca_neg(z, z, ctx); if (ca_check_is_uinf(y, ctx) != T_TRUE || ca_check_is_uinf(z, ctx) != T_TRUE) { flint_printf("FAIL: neg_i_inf\n"); flint_abort(); } ca_i(x, ctx); ca_neg(y, x, ctx); ca_set(z, x, ctx); ca_neg(z, z, ctx); if (ca_check_is_neg_i(y, ctx) != T_TRUE || ca_check_is_neg_i(z, ctx) != T_TRUE) { flint_printf("FAIL: i\n"); flint_abort(); } ca_one(x, ctx); ca_neg(y, x, ctx); ca_set(z, x, ctx); ca_neg(z, z, ctx); if (ca_check_is_neg_one(y, ctx) != T_TRUE || ca_check_is_neg_one(z, ctx) != T_TRUE) { flint_printf("FAIL: one\n"); flint_abort(); } ca_unknown(x, ctx); ca_neg(y, x, ctx); ca_set(z, x, ctx); ca_neg(z, z, ctx); if (!ca_is_unknown(y, ctx) || !ca_is_unknown(z, ctx)) { flint_printf("FAIL: unknown\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-pow.c000066400000000000000000000105211407704557200157170ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("pow...."); fflush(stdout); flint_randinit(state); /* check numerical evaluation */ for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, z; acb_t ax, ay, az, axy; slong prec; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); acb_init(ax); acb_init(ay); acb_init(az); acb_init(axy); prec = 10 + n_randint(state, 100); ca_randtest(x, state, 5, 5, ctx); ca_randtest(y, state, 5, 5, ctx); if (n_randint(state, 2)) ca_exp(x, x, ctx); if (n_randint(state, 2)) { ca_pow(x, x, y, ctx); ca_randtest(y, state, 5, 5, ctx); } ca_pow(z, x, y, ctx); ca_get_acb(ax, x, prec, ctx); ca_get_acb(ay, y, prec, ctx); ca_get_acb(az, z, prec, ctx); acb_pow(axy, ax, ay, prec); if (!acb_overlaps(axy, az)) { flint_printf("FAIL (overlap)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_printf("ax = "); acb_printn(ax, 30, ARB_STR_NO_RADIUS); flint_printf("\n\n"); flint_printf("ay = "); acb_printn(ay, 30, ARB_STR_NO_RADIUS); flint_printf("\n\n"); flint_printf("az = "); acb_printn(az, 30, ARB_STR_NO_RADIUS); flint_printf("\n\n"); flint_printf("axy = "); acb_printn(axy, 30, ARB_STR_NO_RADIUS); flint_printf("\n\n"); flint_abort(); } acb_clear(ax); acb_clear(ay); acb_clear(az); acb_clear(axy); ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_ctx_clear(ctx); } for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, a, b, xa, xb, xaxb, ab, xab; truth_t equal; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(a, ctx); ca_init(b, ctx); ca_init(xa, ctx); ca_init(xb, ctx); ca_init(xaxb, ctx); ca_init(ab, ctx); ca_init(xab, ctx); /* otherwise this will be too slow */ ctx->options[CA_OPT_QQBAR_DEG_LIMIT] = 40; /* x^a * x^b = x^(a+b) */ do { ca_randtest(x, state, 5, 5, ctx); } while (ca_check_is_zero(x, ctx) != T_FALSE); ca_randtest(a, state, 5, 5, ctx); ca_randtest(b, state, 5, 5, ctx); ca_pow(xa, x, a, ctx); ca_pow(xb, x, b, ctx); ca_mul(xaxb, xa, xb, ctx); ca_add(ab, a, b, ctx); ca_pow(xab, x, ab, ctx); equal = ca_check_equal(xab, xaxb, ctx); if (equal == T_FALSE) { flint_printf("FAIL x^a * x^b = x^(a+b)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("a = "); ca_print(a, ctx); flint_printf("\n\n"); flint_printf("b = "); ca_print(b, ctx); flint_printf("\n\n"); flint_printf("xa = "); ca_print(xa, ctx); flint_printf("\n\n"); flint_printf("xb = "); ca_print(xb, ctx); flint_printf("\n\n"); flint_printf("xaxb = "); ca_print(xaxb, ctx); flint_printf("\n\n"); flint_printf("ab = "); ca_print(ab, ctx); flint_printf("\n\n"); flint_printf("xab = "); ca_print(xab, ctx); flint_printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(a, ctx); ca_clear(b, ctx); ca_clear(xa, ctx); ca_clear(xb, ctx); ca_clear(xaxb, ctx); ca_clear(ab, ctx); ca_clear(xab, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-pow_si_arithmetic.c000066400000000000000000000043201407704557200206230ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("pow_si_arithmetic...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, xa, xb, xaxb, xab; truth_t equal; slong a, b; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(xa, ctx); ca_init(xb, ctx); ca_init(xaxb, ctx); ca_init(xab, ctx); /* x^a * x^b = x^(a+b) */ do { ca_randtest(x, state, 5, 5, ctx); } while (ca_check_is_zero(x, ctx) != T_FALSE); a = n_randint(state, 10) - 5; b = n_randint(state, 10) - 5; ca_pow_si_arithmetic(xa, x, a, ctx); ca_pow_si_arithmetic(xb, x, b, ctx); ca_mul(xaxb, xa, xb, ctx); ca_pow_si_arithmetic(xab, x, a + b, ctx); equal = ca_check_equal(xab, xaxb, ctx); if (equal == T_FALSE) { flint_printf("FAIL x^a * x^b = x^(a+b)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("a = %wd", a); flint_printf("\n\n"); flint_printf("b = %wd", b); flint_printf("\n\n"); flint_printf("xa = "); ca_print(xa, ctx); flint_printf("\n\n"); flint_printf("xb = "); ca_print(xb, ctx); flint_printf("\n\n"); flint_printf("xaxb = "); ca_print(xaxb, ctx); flint_printf("\n\n"); flint_printf("xab = "); ca_print(xab, ctx); flint_printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(xa, ctx); ca_clear(xb, ctx); ca_clear(xaxb, ctx); ca_clear(xab, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-properties.c000066400000000000000000000617221407704557200173170ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { flint_rand_t state; flint_printf("properties...."); fflush(stdout); flint_randinit(state); { ca_ctx_t ctx; ca_t x, y; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_zero(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_FALSE); ca_one(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_FALSE); ca_set_si(x, -1, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_FALSE); ca_i(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_FALSE); ca_neg_i(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_FALSE); { fmpq_t q; fmpq_init(q); fmpq_set_si(q, -2, 3); ca_set_fmpq(x, q, ctx); fmpq_clear(q); } CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_FALSE); ca_unknown(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_UNKNOWN); ca_undefined(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_FALSE); ca_uinf(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_FALSE); ca_pos_inf(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_FALSE); ca_neg_inf(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_FALSE); ca_pos_i_inf(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_FALSE); ca_neg_i_inf(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_undefined, "is_undefined", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_infinity, "is_infinity", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_uinf, "is_uinf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_signed_inf, "is_signed_inf", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_pos_inf, "is_pos_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_inf, "is_neg_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_pos_i_inf, "is_pos_i_inf", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i_inf, "is_neg_i_inf", x, ctx, T_TRUE); ca_pi(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_UNKNOWN); /* todo */ CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_UNKNOWN); /* todo */ CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); ca_pi_i(x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_UNKNOWN); /* todo */ CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_TRUE); ca_set_si(x, -400, ctx); ca_exp(x, x, ctx); ca_exp(x, x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); ca_set_si(x, -1000000, ctx); ca_exp(x, x, ctx); ca_exp(x, x, ctx); CA_TEST_PROPERTY(ca_check_is_number, "is_number", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_zero, "is_zero", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_one, "is_one", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_neg_one, "is_neg_one", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_i, "is_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_neg_i, "is_neg_i", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_algebraic, "is_algebraic", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_rational, "is_rational", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_integer, "is_integer", x, ctx, T_UNKNOWN); CA_TEST_PROPERTY(ca_check_is_real, "is_real", x, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_negative_real, "is_negative_real", x, ctx, T_FALSE); CA_TEST_PROPERTY(ca_check_is_imaginary, "is_imaginary", x, ctx, T_FALSE); ca_clear(x, ctx); ca_clear(y, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-re_im.c000066400000000000000000000055531407704557200162160ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("re_im...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, rex, imx, y, absx; truth_t equal; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(rex, ctx); ca_init(imx, ctx); ca_init(y, ctx); ca_init(absx, ctx); ca_randtest(x, state, 5, 5, ctx); ca_re(rex, x, ctx); ca_im(imx, x, ctx); /* test re(x) + im(x)*i = x */ ca_i(y, ctx); ca_mul(y, y, imx, ctx); ca_add(y, y, rex, ctx); equal = ca_check_equal(x, y, ctx); if (equal == T_FALSE) { flint_printf("FAIL (re(x) + im(x)*i != x)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("rex = "); ca_print(rex, ctx); flint_printf("\n\n"); flint_printf("imx = "); ca_print(imx, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_abort(); } CA_TEST_PROPERTY(ca_check_is_real, "is_real", rex, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", imx, ctx, T_TRUE); /* test sqrt(re(x)^2 + im(x)^2) = abs(x) */ ca_sqr(y, rex, ctx); ca_sqr(absx, imx, ctx); ca_add(y, y, absx, ctx); ca_sqrt(y, y, ctx); ca_abs(absx, x, ctx); equal = ca_check_equal(absx, y, ctx); if (equal == T_FALSE) { flint_printf("FAIL (sqrt(re(x)^2 + im(x)^2) != abs(x))\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("rex = "); ca_print(rex, ctx); flint_printf("\n\n"); flint_printf("imx = "); ca_print(imx, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("absx = "); ca_print(absx, ctx); flint_printf("\n\n"); flint_abort(); } CA_TEST_PROPERTY(ca_check_is_real, "is_real", y, ctx, T_TRUE); CA_TEST_PROPERTY(ca_check_is_real, "is_real", absx, ctx, T_TRUE); ca_clear(x, ctx); ca_clear(rex, ctx); ca_clear(imx, ctx); ca_clear(y, ctx); ca_clear(absx, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-sin_cos.c000066400000000000000000000056471407704557200165640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("sin_cos...."); fflush(stdout); flint_randinit(state); { ca_ctx_t ctx; ca_ctx_init(ctx); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { ca_t x, s1, c1, s2, c2, s3, c3, s4, c4; if (n_randint(state, 10) == 0) { ca_ctx_clear(ctx); ca_ctx_init(ctx); } ca_init(x, ctx); ca_init(s1, ctx); ca_init(c1, ctx); ca_init(s2, ctx); ca_init(c2, ctx); ca_init(s3, ctx); ca_init(c3, ctx); ca_init(s4, ctx); ca_init(c4, ctx); ca_randtest_special(x, state, 5, 5, ctx); ca_sin_cos_direct(s1, c1, x, ctx); ca_sin_cos_exponential(s2, c2, x, ctx); ca_sin_cos_tangent(s3, c3, x, ctx); ca_sin_cos(s4, c4, x, ctx); if (ca_check_equal(s1, s2, ctx) == T_FALSE || ca_check_equal(c1, c2, ctx) == T_FALSE || ca_check_equal(s1, s3, ctx) == T_FALSE || ca_check_equal(c1, c3, ctx) == T_FALSE || ca_check_equal(s1, s4, ctx) == T_FALSE || ca_check_equal(c1, c4, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("s1 = "); ca_print(s1, ctx); flint_printf("\n\n"); flint_printf("c1 = "); ca_print(c1, ctx); flint_printf("\n\n"); flint_printf("s2 = "); ca_print(s2, ctx); flint_printf("\n\n"); flint_printf("c2 = "); ca_print(c2, ctx); flint_printf("\n\n"); flint_printf("s3 = "); ca_print(s3, ctx); flint_printf("\n\n"); flint_printf("c3 = "); ca_print(c3, ctx); flint_printf("\n\n"); flint_printf("s4 = "); ca_print(s4, ctx); flint_printf("\n\n"); flint_printf("c4 = "); ca_print(c4, ctx); flint_printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(s1, ctx); ca_clear(c1, ctx); ca_clear(s2, ctx); ca_clear(c2, ctx); ca_clear(s3, ctx); ca_clear(c3, ctx); ca_clear(s4, ctx); ca_clear(c4, ctx); } ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-sqrt.c000066400000000000000000000045651407704557200161160ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("sqrt...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, z, a, b, c, d; truth_t equal; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_init(a, ctx); ca_init(b, ctx); ca_init(c, ctx); ca_init(d, ctx); /* test sqrt(x)^2 = x */ ca_randtest(x, state, 5, 5, ctx); ca_randtest(y, state, 5, 5, ctx); ca_randtest(z, state, 5, 5, ctx); ca_randtest(a, state, 5, 5, ctx); ca_randtest(b, state, 5, 5, ctx); ca_mul(x, x, x, ctx); ca_mul(x, x, z, ctx); ca_sqrt(y, x, ctx); ca_mul(z, y, y, ctx); equal = ca_check_equal(x, z, ctx); if (equal == T_FALSE) { flint_printf("FAIL (sqrt(x)^2 != x)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_abort(); } ca_sqrt_inert(z, x, ctx); equal = ca_check_equal(y, z, ctx); if (equal == T_FALSE) { flint_printf("FAIL: sqrt(x) != sqrt_inert(x)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_clear(a, ctx); ca_clear(b, ctx); ca_clear(c, ctx); ca_clear(d, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-sqrt_factor.c000066400000000000000000000050251407704557200174440ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("sqrt_factor...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, z, a, b, c, d; truth_t equal; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_init(a, ctx); ca_init(b, ctx); ca_init(c, ctx); ca_init(d, ctx); /* test sqrt(x)^2 = x */ ca_randtest_special(x, state, 5, 5, ctx); ca_randtest_special(y, state, 5, 5, ctx); ca_randtest_special(z, state, 5, 5, ctx); ca_randtest_special(a, state, 5, 5, ctx); ca_randtest_special(b, state, 5, 5, ctx); ca_mul(x, x, x, ctx); ca_mul(x, x, z, ctx); /* todo: random flags */ ca_sqrt_factor(y, x, CA_FACTOR_ZZ_SMOOTH | CA_FACTOR_POLY_FULL, ctx); ca_mul(z, y, y, ctx); ca_sub(b, x, z, ctx); equal = ca_check_equal(x, z, ctx); if (equal == T_FALSE) { flint_printf("FAIL (sqrt(x)^2 != x)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_abort(); } ca_sqrt_inert(z, x, ctx); equal = ca_check_equal(y, z, ctx); if (equal == T_FALSE) { flint_printf("FAIL: sqrt(x) != sqrt_inert(x)\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_clear(a, ctx); ca_clear(b, ctx); ca_clear(c, ctx); ca_clear(d, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-sub.c000066400000000000000000000040061407704557200157040ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("sub...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_t x, y, z, a, b; truth_t equal; ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); ca_init(a, ctx); ca_init(b, ctx); /* test (x - y) - z = x - (y + z) */ ca_randtest_special(x, state, 5, 5, ctx); ca_randtest_special(y, state, 5, 5, ctx); ca_randtest_special(z, state, 5, 5, ctx); ca_randtest_special(a, state, 5, 5, ctx); ca_randtest_special(b, state, 5, 5, ctx); ca_sub(a, x, y, ctx); ca_sub(a, a, z, ctx); ca_add(b, y, z, ctx); ca_sub(b, x, b, ctx); equal = ca_check_equal(a, b, ctx); if (equal == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_printf("a = "); ca_print(a, ctx); flint_printf("\n\n"); flint_printf("b = "); ca_print(b, ctx); flint_printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_clear(a, ctx); ca_clear(b, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-tan.c000066400000000000000000000042231407704557200156760ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("tan..."); fflush(stdout); flint_randinit(state); { ca_ctx_t ctx; ca_ctx_init(ctx); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { ca_t x, t1, t2, t3, t4; if (n_randint(state, 10) == 0) { ca_ctx_clear(ctx); ca_ctx_init(ctx); } ca_init(x, ctx); ca_init(t1, ctx); ca_init(t2, ctx); ca_init(t3, ctx); ca_init(t4, ctx); ca_randtest_special(x, state, 5, 5, ctx); ca_tan_direct(t1, x, ctx); ca_tan_exponential(t2, x, ctx); ca_tan_sine_cosine(t3, x, ctx); ca_tan(t4, x, ctx); if (ca_check_equal(t1, t2, ctx) == T_FALSE || ca_check_equal(t1, t3, ctx) == T_FALSE || ca_check_equal(t1, t4, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("t1 = "); ca_print(t1, ctx); flint_printf("\n\n"); flint_printf("t2 = "); ca_print(t2, ctx); flint_printf("\n\n"); flint_printf("t3 = "); ca_print(t3, ctx); flint_printf("\n\n"); flint_printf("t4 = "); ca_print(t4, ctx); flint_printf("\n\n"); flint_abort(); } ca_clear(x, ctx); ca_clear(t1, ctx); ca_clear(t2, ctx); ca_clear(t3, ctx); ca_clear(t4, ctx); } ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/test/t-transfer.c000066400000000000000000000042751407704557200167470ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" int main() { slong iter; flint_rand_t state; flint_printf("transfer...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx, ctx2; ca_t x, y, z; slong i, reps; ca_ctx_init(ctx); ca_ctx_init(ctx2); ca_init(x, ctx); ca_init(y, ctx2); ca_init(z, ctx); reps = 1 + n_randint(state, 10); for (i = 0; i < reps; i++) { ca_randtest_special(x, state, 5, 5, ctx); ca_randtest_special(y, state, 5, 5, ctx2); ca_randtest_special(z, state, 5, 5, ctx); ca_transfer(y, ctx2, x, ctx); ca_transfer(z, ctx, y, ctx2); if (ca_check_equal(x, z, ctx) == T_FALSE) { flint_printf("FAIL: not equal!\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx2); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_abort(); } if (ca_check_equal(x, z, ctx) != T_TRUE && !ca_is_unknown(x, ctx)) { flint_printf("FAIL: not equal!\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n\n"); flint_printf("y = "); ca_print(y, ctx2); flint_printf("\n\n"); flint_printf("z = "); ca_print(z, ctx); flint_printf("\n\n"); flint_abort(); } } ca_clear(x, ctx); ca_clear(y, ctx2); ca_clear(z, ctx); ca_ctx_clear(ctx); ca_ctx_clear(ctx2); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca/transfer.c000066400000000000000000000021701407704557200155170ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_transfer(ca_t res, ca_ctx_t res_ctx, const ca_t src, ca_ctx_t src_ctx) { if (res_ctx == src_ctx) { ca_set(res, src, res_ctx); } else if (CA_IS_QQ(src, src_ctx)) { _ca_make_fmpq(res, res_ctx); fmpq_set(CA_FMPQ(res), CA_FMPQ(src)); } else { fexpr_t expr; fexpr_init(expr); /* todo: optimizations, e.g. direct transfer of number field elements where permissible */ ca_get_fexpr(expr, src, CA_FEXPR_SERIALIZATION, src_ctx); if (!ca_set_fexpr(res, expr, res_ctx)) { flint_printf("ca_transfer: failed to recreate from expression!\n"); flint_abort(); } fexpr_clear(expr); } } calcium-0.4.1/ca/uinf.c000066400000000000000000000007501407704557200146360ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_uinf(ca_t x, ca_ctx_t ctx) { ca_zero(x, ctx); x->field = CA_INF; } calcium-0.4.1/ca/undefined.c000066400000000000000000000007641407704557200156430ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_undefined(ca_t x, ca_ctx_t ctx) { ca_zero(x, ctx); x->field = CA_UNDEFINED; } calcium-0.4.1/ca/unknown.c000066400000000000000000000007601407704557200153750ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_unknown(ca_t x, ca_ctx_t ctx) { ca_zero(x, ctx); x->field = CA_UNKNOWN; } calcium-0.4.1/ca/zero.c000066400000000000000000000007631407704557200146600ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" void ca_zero(ca_t x, ca_ctx_t ctx) { _ca_make_fmpq(x, ctx); fmpq_zero(CA_FMPQ(x)); } calcium-0.4.1/ca_ext.h000066400000000000000000000052461407704557200145670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef CA_EXT_H #define CA_EXT_H #ifdef CA_EXT_INLINES_C #define CA_EXT_INLINE #else #define CA_EXT_INLINE static __inline__ #endif #include "calcium.h" #include "qqbar.h" #include "ca.h" #ifdef __cplusplus extern "C" { #endif /* Types *********************************************************************/ /* note: types and macros are defined in ca.h since they are needed there */ void ca_ext_init_qqbar(ca_ext_t res, const qqbar_t x, ca_ctx_t ctx); void ca_ext_init_const(ca_ext_t res, calcium_func_code func, ca_ctx_t ctx); void ca_ext_init_fx(ca_ext_t res, calcium_func_code func, const ca_t x, ca_ctx_t ctx); void ca_ext_init_fxy(ca_ext_t res, calcium_func_code func, const ca_t x, const ca_t y, ca_ctx_t ctx); void ca_ext_init_fxn(ca_ext_t res, calcium_func_code func, ca_srcptr x, slong nargs, ca_ctx_t ctx); /* todo: this could avoid rehashing, ... */ CA_EXT_INLINE void ca_ext_init_set(ca_ext_t res, const ca_ext_t x, ca_ctx_t ctx) { if (CA_EXT_HEAD(x) == CA_QQBar) { ca_ext_init_qqbar(res, CA_EXT_QQBAR(x), ctx); } else { ca_ext_init_fxn(res, CA_EXT_HEAD(x), CA_EXT_FUNC_ARGS(x), CA_EXT_FUNC_NARGS(x), ctx); } } void ca_ext_clear(ca_ext_t res, ca_ctx_t ctx); CA_EXT_INLINE slong ca_ext_nargs(const ca_ext_t x, ca_ctx_t ctx) { if (CA_EXT_HEAD(x) == CA_QQBar) return 0; else return CA_EXT_FUNC_NARGS(x); } CA_EXT_INLINE void ca_ext_get_arg(ca_t res, const ca_ext_t x, slong i, ca_ctx_t ctx) { if (CA_EXT_HEAD(x) == CA_QQBar || i < 0 || i >= CA_EXT_FUNC_NARGS(x)) { flint_printf("ca_ext_get_arg: index out of range\n"); flint_abort(); } else { ca_set(res, CA_EXT_FUNC_ARGS(x) + i, ctx); } } CA_EXT_INLINE ulong ca_ext_hash(const ca_ext_t x, ca_ctx_t ctx) { return CA_EXT_HASH(x); } int ca_ext_equal_repr(const ca_ext_t x, const ca_ext_t y, ca_ctx_t ctx); int ca_ext_cmp_repr(const ca_ext_t x, const ca_ext_t y, ca_ctx_t ctx); void ca_ext_print(const ca_ext_t x, ca_ctx_t ctx); void ca_ext_get_acb_raw(acb_t res, ca_ext_t x, slong prec, ca_ctx_t ctx); void ca_ext_cache_init(ca_ext_cache_t cache, ca_ctx_t ctx); void ca_ext_cache_clear(ca_ext_cache_t cache, ca_ctx_t ctx); ca_ext_ptr ca_ext_cache_insert(ca_ext_cache_t cache, const ca_ext_t x, ca_ctx_t ctx); #ifdef __cplusplus } #endif #endif calcium-0.4.1/ca_ext/000077500000000000000000000000001407704557200144075ustar00rootroot00000000000000calcium-0.4.1/ca_ext/cache_clear.c000066400000000000000000000014551407704557200167710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_ext.h" void ca_ext_cache_clear(ca_ext_cache_t cache, ca_ctx_t ctx) { slong i; /* reverse order ensures that we free f(x) before freeing any element used by x */ for (i = cache->length - 1; i >= 0; i--) ca_ext_clear(cache->items[i], ctx); for (i = 0; i < cache->alloc; i++) flint_free(cache->items[i]); flint_free(cache->items); flint_free(cache->hash_table); } calcium-0.4.1/ca_ext/cache_init.c000066400000000000000000000014161407704557200166430ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_ext.h" #define INITIAL_HASH_SIZE 16 void ca_ext_cache_init(ca_ext_cache_t cache, ca_ctx_t ctx) { slong i; cache->items = NULL; cache->length = 0; cache->alloc = 0; cache->hash_size = INITIAL_HASH_SIZE; cache->hash_table = flint_malloc(sizeof(slong) * INITIAL_HASH_SIZE); for (i = 0; i < INITIAL_HASH_SIZE; i++) cache->hash_table[i] = -1; } calcium-0.4.1/ca_ext/cache_insert.c000066400000000000000000000046271407704557200172130ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_ext.h" ca_ext_ptr ca_ext_cache_insert(ca_ext_cache_t cache, const ca_ext_t x, ca_ctx_t ctx) { ulong xhash; slong i, loc; xhash = ca_ext_hash(x, ctx); /* make room for inserting entry if needed */ if (cache->length == cache->alloc) { slong new_alloc; new_alloc = FLINT_MAX(1, cache->alloc * 2); cache->items = flint_realloc(cache->items, sizeof(ca_ext_struct *) * new_alloc); for (i = cache->alloc; i < new_alloc; i++) cache->items[i] = flint_malloc(sizeof(ca_ext_struct)); cache->alloc = new_alloc; } /* rehash if needed */ if (cache->length >= 0.5 * cache->hash_size) { slong new_size, j; slong * new_table; ulong thash; new_size = cache->hash_size * 2; new_table = flint_malloc(sizeof(slong) * new_size); for (i = 0; i < new_size; i++) new_table[i] = -1; for (i = 0; i < cache->length; i++) { thash = ca_ext_hash(cache->items[i], ctx); j = thash % new_size; while (new_table[j] != -1) { j++; if (j == new_size) j = 0; } new_table[j] = i; } flint_free(cache->hash_table); cache->hash_size = new_size; cache->hash_table = new_table; } loc = xhash % ((ulong) cache->hash_size); for (i = 0; i < cache->hash_size; i++) { /* not found, so insert */ if (cache->hash_table[loc] == -1) { ca_ext_init_set(cache->items[cache->length], x, ctx); cache->hash_table[loc] = cache->length; cache->length++; return cache->items[cache->length - 1]; } /* found */ if (ca_ext_equal_repr(cache->items[cache->hash_table[loc]], x, ctx)) return cache->items[cache->hash_table[loc]]; loc++; if (loc == cache->hash_size) loc = 0; } /* cannot happen */ flint_abort(); } calcium-0.4.1/ca_ext/clear.c000066400000000000000000000017641407704557200156510ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_ext.h" #include "ca_vec.h" void ca_ext_clear(ca_ext_t res, ca_ctx_t ctx) { if (CA_EXT_HEAD(res) == CA_QQBar) { qqbar_clear(CA_EXT_QQBAR(res)); nf_clear(CA_EXT_QQBAR_NF(res)); flint_free(CA_EXT_QQBAR_NF(res)); } else { if (CA_EXT_FUNC_NARGS(res) != 0) _ca_vec_clear(CA_EXT_FUNC_ARGS(res), CA_EXT_FUNC_NARGS(res), ctx); acb_clear(CA_EXT_FUNC_ENCLOSURE(res)); if (res->data.func_data.qqbar != NULL) { qqbar_clear(res->data.func_data.qqbar); flint_free(res->data.func_data.qqbar); } } } calcium-0.4.1/ca_ext/cmp_repr.c000066400000000000000000000046171407704557200163720ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_ext.h" static int _fmpz_poly_compare_abslex(const fmpz * a, const fmpz * b, slong len) { slong i; int c; for (i = len - 1; i >= 0; i--) { if (!fmpz_equal(a + i, b + i)) { c = fmpz_cmpabs(a + i, b + i); if (c != 0) return (c > 0) ? 1 : -1; return fmpz_sgn(a + i); } } return 0; } static int _qqbar_cmp_repr(const qqbar_t x1, const qqbar_t x2) { slong d1, d2; int c; d1 = qqbar_degree(x1); d2 = qqbar_degree(x2); if (d1 != d2) return (d1 < d2) ? -1 : 1; c = _fmpz_poly_compare_abslex(QQBAR_COEFFS(x1), QQBAR_COEFFS(x2), d1 + 1); if (c != 0) return c; /* todo: different sort order? */ c = qqbar_cmp_re(x1, x2); if (c != 0) return c; c = qqbar_cmp_im(x1, x2); return c; } slong ca_depth(const ca_t x, ca_ctx_t ctx); int ca_ext_cmp_repr(const ca_ext_t x, const ca_ext_t y, ca_ctx_t ctx) { calcium_func_code head1, head2; slong i, len1, len2, depth1, depth2; head1 = CA_EXT_HEAD(x); head2 = CA_EXT_HEAD(y); if (x == y) return 0; if (head1 == CA_QQBar || head2 == CA_QQBar) { if (head1 == head2) return _qqbar_cmp_repr(CA_EXT_QQBAR(x), CA_EXT_QQBAR(y)); if (head1 == CA_QQBar) return -1; else return 1; } /* Depth comparison: this is a hack to sort f(x) before x, so that lex ordering can give an elimination order. */ depth1 = CA_EXT_DEPTH(x); depth2 = CA_EXT_DEPTH(y); if (depth1 < depth2) return -1; if (depth1 > depth2) return 1; len1 = CA_EXT_FUNC_NARGS(x); len2 = CA_EXT_FUNC_NARGS(y); if (head1 != head2) return (head1 < head2) ? -1 : 1; if (len1 != len2) return (len1 < len2) ? -1 : 1; for (i = 0; i < len1; i++) { int c = ca_cmp_repr(CA_EXT_FUNC_ARGS(x) + i, CA_EXT_FUNC_ARGS(y) + i, ctx); if (c != 0) return c; } return 0; } calcium-0.4.1/ca_ext/equal_repr.c000066400000000000000000000017131407704557200167140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_ext.h" int ca_ext_equal_repr(const ca_ext_t x, const ca_ext_t y, ca_ctx_t ctx) { slong i, nargs; if (CA_EXT_HASH(x) != CA_EXT_HASH(y)) return 0; if (CA_EXT_HEAD(x) != CA_EXT_HEAD(y)) return 0; if (CA_EXT_HEAD(x) == CA_QQBar) return qqbar_equal(CA_EXT_QQBAR(x), CA_EXT_QQBAR(y)); nargs = CA_EXT_FUNC_NARGS(x); if (nargs != CA_EXT_FUNC_NARGS(y)) return 0; for (i = 0; i < nargs; i++) if (!ca_equal_repr(CA_EXT_FUNC_ARGS(x) + i, CA_EXT_FUNC_ARGS(y) + i, ctx)) return 0; return 1; } calcium-0.4.1/ca_ext/get_acb_raw.c000066400000000000000000000103431407704557200170110ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "acb_hypgeom.h" #include "ca_ext.h" #define ARB_CONST(f) \ f(acb_realref(res), prec); \ arb_zero(acb_imagref(res)); \ break; #define ACB_UNARY(f) \ ca_get_acb_raw(res, CA_EXT_FUNC_ARGS(x), prec, ctx); \ f(res, res, prec); \ break; #define ACB_UNARY_NOPREC(f) \ ca_get_acb_raw(res, CA_EXT_FUNC_ARGS(x), prec, ctx); \ f(res, res); \ break; #define ACB_UNARY_REAL(f) \ ca_get_acb_raw(res, CA_EXT_FUNC_ARGS(x), prec, ctx); \ f(acb_realref(res), res, prec); \ arb_zero(acb_imagref(res)); \ break; #define ACB_UNARY_REAL_NOPREC(f) \ ca_get_acb_raw(res, CA_EXT_FUNC_ARGS(x), prec, ctx); \ f(acb_realref(res), res); \ arb_zero(acb_imagref(res)); \ break; #define ACB_UNARY_REAL_REAL(f) \ ca_get_acb_raw(res, CA_EXT_FUNC_ARGS(x), prec, ctx); \ f(acb_realref(res), acb_realref(res), prec); \ arb_zero(acb_imagref(res)); \ break; #define ACB_BINARY(f) \ { \ acb_t _t; \ acb_init(_t); \ ca_get_acb_raw(res, CA_EXT_FUNC_ARGS(x), prec, ctx); \ ca_get_acb_raw(_t, CA_EXT_FUNC_ARGS(x) + 1, prec, ctx); \ f(res, res, _t, prec); \ acb_clear(_t); \ } \ break; void ca_ext_get_acb_raw(acb_t res, ca_ext_t x, slong prec, ca_ctx_t ctx) { if (CA_EXT_HEAD(x) == CA_QQBar) { qqbar_cache_enclosure(CA_EXT_QQBAR(x), prec); qqbar_get_acb(res, CA_EXT_QQBAR(x), prec); return; } if (prec <= CA_EXT_FUNC_PREC(x)) { acb_set(res, CA_EXT_FUNC_ENCLOSURE(x)); return; } switch (CA_EXT_HEAD(x)) { /* Arithmetic */ case CA_Neg: ACB_UNARY_NOPREC(acb_neg) case CA_Add: ACB_BINARY(acb_add) case CA_Sub: ACB_BINARY(acb_sub) case CA_Mul: ACB_BINARY(acb_mul) case CA_Div: ACB_BINARY(acb_div) /* Roots */ case CA_Sqrt: ACB_UNARY(acb_sqrt) /* CA_Cbrt, not implemented */ /* CA_Root, not implemented */ /* Complex parts */ case CA_Floor: ACB_UNARY_REAL_REAL(arb_floor) case CA_Ceil: ACB_UNARY_REAL_REAL(arb_ceil) case CA_Abs: ACB_UNARY_REAL(acb_abs) case CA_Sign: ACB_UNARY(acb_sgn) case CA_Re: ACB_UNARY_REAL_NOPREC(acb_get_real) case CA_Im: ACB_UNARY_REAL_NOPREC(acb_get_imag) case CA_Arg: ACB_UNARY_REAL(acb_arg) case CA_Conjugate: ACB_UNARY_NOPREC(acb_conj) /* Elementary constants */ case CA_Pi: ARB_CONST(arb_const_pi) /* Elementary functions */ case CA_Exp: ACB_UNARY(acb_exp) case CA_Log: ACB_UNARY(acb_log) case CA_Pow: ACB_BINARY(acb_pow) case CA_Cos: ACB_UNARY(acb_cos) case CA_Sin: ACB_UNARY(acb_sin) case CA_Tan: ACB_UNARY(acb_tan) case CA_Cosh: ACB_UNARY(acb_cosh) case CA_Sinh: ACB_UNARY(acb_sinh) case CA_Tanh: ACB_UNARY(acb_tanh) case CA_Atan: ACB_UNARY(acb_atan) case CA_Acos: ACB_UNARY(acb_acos) case CA_Asin: ACB_UNARY(acb_asin) case CA_Atanh: ACB_UNARY(acb_atanh) case CA_Acosh: ACB_UNARY(acb_acosh) case CA_Asinh: ACB_UNARY(acb_asinh) /* Euler's constant */ case CA_Euler: ARB_CONST(arb_const_euler) /* Gamma and related functions */ case CA_Gamma: ACB_UNARY(acb_gamma) case CA_LogGamma: ACB_UNARY(acb_lgamma) case CA_Psi: ACB_UNARY(acb_digamma) case CA_Erf: ACB_UNARY(acb_hypgeom_erf) case CA_Erfc: ACB_UNARY(acb_hypgeom_erfc) case CA_Erfi: ACB_UNARY(acb_hypgeom_erfi) case CA_RiemannZeta: ACB_UNARY(acb_zeta) case CA_HurwitzZeta: ACB_BINARY(acb_hurwitz_zeta) default: flint_printf("ca_ext_get_acb_raw: unknown function\n"); flint_abort(); } acb_set(CA_EXT_FUNC_ENCLOSURE(x), res); CA_EXT_FUNC_PREC(x) = prec; } calcium-0.4.1/ca_ext/init.c000066400000000000000000000060271407704557200155230ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_ext.h" #include "ca_vec.h" static ulong hash_func(calcium_func_code func, ca_srcptr args, slong nargs, ca_ctx_t ctx) { ulong s; slong i; s = func; for (i = 0; i < nargs; i++) s = ca_hash_repr(args + i, ctx) * 1000003 + s; return s; } void ca_ext_init_qqbar(ca_ext_t res, const qqbar_t x, ca_ctx_t ctx) { fmpq_poly_t t; res->head = CA_QQBar; qqbar_init(CA_EXT_QQBAR(res)); qqbar_set(CA_EXT_QQBAR(res), x); /* qqbar_cache_enclosure(CA_EXT_QQBAR(res), 2 * QQBAR_DEFAULT_PREC); */ /* nf_init wants an fmpq_poly_t, so mock up one */ t->coeffs = QQBAR_POLY(x)->coeffs; t->den[0] = 1; t->length = QQBAR_POLY(x)->length; t->alloc = QQBAR_POLY(x)->alloc; CA_EXT_QQBAR_NF(res) = flint_malloc(sizeof(nf_struct)); nf_init(CA_EXT_QQBAR_NF(res), t); res->hash = qqbar_hash(CA_EXT_QQBAR(res)); res->depth = 0; } slong ca_depth(const ca_t x, ca_ctx_t ctx); static void _ca_ext_init_func(ca_ext_t res, ca_ctx_t ctx) { slong i, d; CA_EXT_FUNC_PREC(res) = 0; acb_init(CA_EXT_FUNC_ENCLOSURE(res)); acb_indeterminate(CA_EXT_FUNC_ENCLOSURE(res)); res->hash = hash_func(CA_EXT_HEAD(res), CA_EXT_FUNC_ARGS(res), CA_EXT_FUNC_NARGS(res), ctx); res->depth = 0; for (i = 0; i < CA_EXT_FUNC_NARGS(res); i++) { d = ca_depth(CA_EXT_FUNC_ARGS(res) + i, ctx); res->depth = FLINT_MAX(res->depth, d + 1); } res->data.func_data.qqbar = NULL; } void ca_ext_init_const(ca_ext_t res, calcium_func_code func, ca_ctx_t ctx) { res->head = func; CA_EXT_FUNC_NARGS(res) = 0; CA_EXT_FUNC_ARGS(res) = NULL; _ca_ext_init_func(res, ctx); } void ca_ext_init_fx(ca_ext_t res, calcium_func_code func, const ca_t x, ca_ctx_t ctx) { res->head = func; res->hash = 0; CA_EXT_FUNC_NARGS(res) = 1; CA_EXT_FUNC_ARGS(res) = _ca_vec_init(1, ctx); ca_set(CA_EXT_FUNC_ARGS(res), x, ctx); _ca_ext_init_func(res, ctx); } void ca_ext_init_fxy(ca_ext_t res, calcium_func_code func, const ca_t x, const ca_t y, ca_ctx_t ctx) { res->head = func; res->hash = 0; CA_EXT_FUNC_NARGS(res) = 2; CA_EXT_FUNC_ARGS(res) = _ca_vec_init(2, ctx); ca_set(CA_EXT_FUNC_ARGS(res), x, ctx); ca_set(CA_EXT_FUNC_ARGS(res) + 1, y, ctx); _ca_ext_init_func(res, ctx); } void ca_ext_init_fxn(ca_ext_t res, calcium_func_code func, ca_srcptr x, slong nargs, ca_ctx_t ctx) { res->head = func; CA_EXT_FUNC_NARGS(res) = nargs; if (nargs == 0) CA_EXT_FUNC_ARGS(res) = NULL; else CA_EXT_FUNC_ARGS(res) = _ca_vec_init(nargs, ctx); _ca_vec_set(CA_EXT_FUNC_ARGS(res), x, nargs, ctx); _ca_ext_init_func(res, ctx); } calcium-0.4.1/ca_ext/inlines.c000066400000000000000000000006621407704557200162200ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #define CA_EXT_INLINES_C #include "ca_ext.h" calcium-0.4.1/ca_ext/print.c000066400000000000000000000026221407704557200157110ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_ext.h" void ca_ext_print(const ca_ext_t x, ca_ctx_t ctx) { if (x->head == CA_QQBar) { flint_printf("Algebraic "); if (qqbar_is_i(CA_EXT_QQBAR(x))) flint_printf("I"); else { /* flint_printf("Algebraic [deg %wd] ", qqbar_degree(CA_EXT_QQBAR(x))); qqbar_printn(CA_EXT_QQBAR(x), 10); */ qqbar_printn(CA_EXT_QQBAR(x), 8); /* flint_printf(" ("); fmpz_poly_print_pretty(QQBAR_POLY(CA_EXT_QQBAR(x)), "a"); flint_printf("=0)"); */ } } else { flint_printf("%s", calcium_func_name(CA_EXT_HEAD(x))); if (CA_EXT_FUNC_NARGS(x) != 0) { slong i; flint_printf("("); for (i = 0; i < CA_EXT_FUNC_NARGS(x); i++) { ca_print(CA_EXT_FUNC_ARGS(x) + i, ctx); if (i < CA_EXT_FUNC_NARGS(x) - 1) flint_printf(", "); } flint_printf(")"); } } } calcium-0.4.1/ca_ext/test/000077500000000000000000000000001407704557200153665ustar00rootroot00000000000000calcium-0.4.1/ca_ext/test/t-cache_insert.c000066400000000000000000000033431407704557200204250ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" int main() { slong iter; flint_rand_t state; flint_printf("cache_insert...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_ext_t ext; ca_ext_ptr ext2; ca_ext_cache_t cache; qqbar_t x; slong i, len; ca_ctx_init(ctx); qqbar_init(x); len = n_randint(state, 1000); ca_ext_cache_init(cache, ctx); for (i = 0; i < len; i++) { qqbar_set_ui(x, n_randint(state, 100)); ca_ext_init_qqbar(ext, x, ctx); ext2 = ca_ext_cache_insert(cache, ext, ctx); if (!ca_ext_equal_repr(ext2, ext, ctx)) { flint_printf("FAIL\n\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("ext = "); ca_ext_print(ext, ctx); flint_printf("\n\n"); flint_printf("ext2 = "); ca_ext_print(ext2, ctx); flint_printf("\n\n"); flint_abort(); } ca_ext_clear(ext, ctx); } ca_ext_cache_clear(cache, ctx); ca_ctx_clear(ctx); qqbar_clear(x); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_field.h000066400000000000000000000036721407704557200150530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef CA_FIELD_H #define CA_FIELD_H #ifdef CA_FIELD_INLINES_C #define CA_FIELD_INLINE #else #define CA_FIELD_INLINE static __inline__ #endif #include "calcium.h" #include "ca.h" #ifdef __cplusplus extern "C" { #endif /* Types *********************************************************************/ /* note: types and macros are defined in ca.h since they are needed there */ #define CA_FIELD_HASH_C UWORD(100003) void ca_field_init_qq(ca_field_t K, ca_ctx_t ctx); void ca_field_init_nf(ca_field_t K, const qqbar_t x, ca_ctx_t ctx); void ca_field_init_const(ca_field_t K, calcium_func_code func, ca_ctx_t ctx); void ca_field_init_fx(ca_field_t K, calcium_func_code func, const ca_t x, ca_ctx_t ctx); void ca_field_init_fxy(ca_field_t K, calcium_func_code func, const ca_t x, const ca_t y, ca_ctx_t ctx); void ca_field_init_multi(ca_field_t K, slong len, ca_ctx_t ctx); void ca_field_clear(ca_field_t K, ca_ctx_t ctx); void ca_field_set_ext(ca_field_t K, slong i, ca_ext_srcptr x, ca_ctx_t ctx); void ca_field_print(const ca_field_t K, ca_ctx_t ctx); int ca_field_cmp(const ca_field_t K1, const ca_field_t K2, ca_ctx_t ctx); void ca_field_build_ideal(ca_field_t K, ca_ctx_t ctx); void ca_field_build_ideal_erf(ca_field_t K, ca_ctx_t ctx); void ca_field_build_ideal_gamma(ca_field_t K, ca_ctx_t ctx); void ca_field_cache_init(ca_field_cache_t cache, ca_ctx_t ctx); void ca_field_cache_clear(ca_field_cache_t cache, ca_ctx_t ctx); ca_field_ptr ca_field_cache_insert_ext(ca_field_cache_t cache, ca_ext_struct ** x, slong length, ca_ctx_t ctx); #ifdef __cplusplus } #endif #endif calcium-0.4.1/ca_field/000077500000000000000000000000001407704557200146725ustar00rootroot00000000000000calcium-0.4.1/ca_field/build_ideal.c000066400000000000000000001012271407704557200172760ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" #include "flint/fmpz_lll.h" #include "qqbar.h" #include "utils_flint.h" int qqbar_mul_checked(qqbar_t res, const qqbar_t x, const qqbar_t y, slong deg_limit, slong bits_limit); int qqbar_pow_fmpz_checked(qqbar_t res, const qqbar_t x, const fmpz_t y, slong deg_limit, slong bits_limit); slong acb_multi_lindep(fmpz_mat_t rel, acb_srcptr vec, slong len, int check, slong prec) { fmpz_mat_t A; arf_t tmpr, halfr; fmpz_lll_t ctx; fmpz_t scale_exp; int nonreal, found; slong i, row, accuracy; acb_t z2; mag_t max_size, max_rad, tmpmag; if (fmpz_mat_nrows(rel) != 0 || fmpz_mat_ncols(rel) != 0) flint_abort(); fmpz_mat_clear(rel); for (i = 0; i < len; i++) { if (!acb_is_finite(vec + i)) { fmpz_mat_init(rel, 0, len); return 0; } } found = 0; nonreal = 0; for (i = 0; i < len; i++) if (!arb_contains_zero(acb_imagref(vec + i))) nonreal = 1; fmpz_mat_init(A, len, len + 1 + nonreal); fmpz_init(scale_exp); acb_init(z2); arf_init(tmpr); arf_init(halfr); mag_init(max_size); mag_init(max_rad); mag_init(tmpmag); arf_set_d(halfr, 0.5); for (i = 0; i < len; i++) { arf_get_mag(tmpmag, arb_midref(acb_realref(vec + i))); mag_max(max_size, max_size, tmpmag); arf_get_mag(tmpmag, arb_midref(acb_imagref(vec + i))); mag_max(max_size, max_size, tmpmag); mag_max(max_rad, max_rad, arb_radref(acb_realref(vec + i))); mag_max(max_rad, max_rad, arb_radref(acb_imagref(vec + i))); } prec = FLINT_MAX(prec, 2); if (!mag_is_zero(max_size) && !mag_is_zero(max_rad)) { accuracy = _fmpz_sub_small(MAG_EXPREF(max_size), MAG_EXPREF(max_rad)); accuracy = FLINT_MAX(accuracy, 10); prec = FLINT_MIN(prec, accuracy); } if (mag_is_zero(max_size)) { fmpz_zero(scale_exp); /* todo: quick return? */ } else { fmpz_neg(scale_exp, MAG_EXPREF(max_size)); fmpz_add_ui(scale_exp, scale_exp, prec); } /* Using 5% of the bits for checking will provide some protection against spurious relations */ fmpz_sub_ui(scale_exp, scale_exp, FLINT_MAX(10, prec * 0.05)); /* Create matrix */ for (i = 0; i < len; i++) fmpz_one(fmpz_mat_entry(A, i, i)); for (i = 0; i < len; i++) { arf_mul_2exp_fmpz(tmpr, arb_midref(acb_realref(vec + i)), scale_exp); arf_add(tmpr, tmpr, halfr, prec, ARF_RND_NEAR); arf_floor(tmpr, tmpr); arf_get_fmpz(fmpz_mat_entry(A, i, len), tmpr, ARF_RND_NEAR); if (nonreal) { arf_mul_2exp_fmpz(tmpr, arb_midref(acb_imagref(vec + i)), scale_exp); arf_add(tmpr, tmpr, halfr, prec, ARF_RND_NEAR); arf_floor(tmpr, tmpr); arf_get_fmpz(fmpz_mat_entry(A, i, len + 1), tmpr, ARF_RND_NEAR); } } /* LLL reduction */ fmpz_lll_context_init(ctx, 0.75, 0.51, 1, 0); #if 1 fmpz_lll(A, NULL, ctx); #else { fmpz_t gb; fmpz_init(gb); fmpz_one(gb); fmpz_mul_2exp(gb, gb, prec / 2); fmpz_lll_with_removal(A, NULL, gb, ctx); fmpz_clear(gb); } #endif /* Heuristic check */ for (row = 0; row < len; row++) { acb_zero(z2); for (i = 0; i < len; i++) acb_addmul_fmpz(z2, vec + i, fmpz_mat_entry(A, row, i), prec + 10); if (!_fmpz_vec_is_zero(A->rows[row], len) && acb_contains_zero(z2)) { found++; } else { _fmpz_vec_zero(A->rows[row], fmpz_mat_ncols(A)); } } fmpz_mat_init(rel, found, len); i = 0; for (row = 0; row < len; row++) { if (!_fmpz_vec_is_zero(A->rows[row], len)) { _fmpz_vec_set(rel->rows[i], A->rows[row], len); i++; } } /* todo: move outside? */ if (found > 1) { fmpz_mat_hnf(rel, rel); } fmpz_mat_clear(A); fmpz_clear(scale_exp); acb_clear(z2); arf_clear(tmpr); arf_clear(halfr); mag_clear(max_size); mag_clear(max_rad); mag_clear(tmpmag); /* fixme: bogus */ return found; } void _nf_elem_get_fmpz_poly_den_shallow(fmpz_poly_t pol, fmpz_t den, const nf_elem_t a, const nf_t nf); void _ca_field_ideal_insert_clear_mpoly(ca_field_t K, fmpz_mpoly_t poly, fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx) { if (poly->length == 0) { flint_printf("ERROR: inserting the zero polynomial into ideal\n"); flint_abort(); } if (fmpz_sgn(poly->coeffs) < 0) fmpz_mpoly_neg(poly, poly, mctx); /* todo: move!!! */ fmpz_mpoly_vec_insert_unique(CA_FIELD_IDEAL(K), poly, mctx); fmpz_mpoly_clear(poly, mctx); } int ext_as_pow_pq(slong *p, slong *q, const ca_ext_t x, ca_ctx_t ctx) { if (CA_EXT_HEAD(x) == CA_Sqrt) { *p = 1; *q = 2; return 1; } if (CA_EXT_HEAD(x) == CA_Pow && CA_IS_QQ(CA_EXT_FUNC_ARGS(x) + 1, ctx)) { fmpz pp, qq; pp = *CA_FMPQ_NUMREF(CA_EXT_FUNC_ARGS(x) + 1); qq = *CA_FMPQ_DENREF(CA_EXT_FUNC_ARGS(x) + 1); if (fmpz_bits(&pp) <= 6 && fmpz_bits(&qq) <= 6) { *p = fmpz_get_si(&pp); *q = fmpz_get_si(&qq); return 1; } } return 0; } int ca_field_prove_log_relation(ca_field_t K, const fmpz * rel, acb_srcptr z, const slong * logs, slong num_logs, slong num_logs_with_pi_i, slong prec, ca_ctx_t ctx) { ca_t prod, upow; slong j; acb_t t; mag_t tm; int success = 0; /* printf("possible log relation!\n"); for (j = 0; j < num_logs; j++) { fmpz_print(rel + j); printf(" "); acb_printn(z + j, 10, 0); printf(" "); } printf("\n"); */ acb_init(t); mag_init(tm); /* a^m * b^n = 1 => m*log(a) + n*log(b) = 2 pi i k */ /* Verify that (m*log(a) + n*log(b)) / (2 pi i) contains unique integer. */ /* It is enough to show that |... + ...| < 2^1. */ acb_zero(t); for (j = 0; j < num_logs_with_pi_i; j++) if (!fmpz_is_zero(rel + j)) acb_addmul_fmpz(t, z + j, rel + j, prec); acb_get_mag(tm, t); if (mag_cmp_2exp_si(tm, 1) < 0) { ca_init(prod, ctx); ca_init(upow, ctx); /* Check product of arguments to log. */ /* Todo: separate positive/negative exponents, thus avoiding inverses? */ /* Or: otherwise balance the product. */ ca_one(prod, ctx); for (j = 0; j < num_logs; j++) { if (!fmpz_is_zero(rel + j)) { ca_pow_fmpz(upow, CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, logs[j])), rel + j, ctx); ca_mul(prod, prod, upow, ctx); } } /* printf("product: "); ca_print(prod, ctx); printf("\n\n"); */ success = (ca_check_is_one(prod, ctx) == T_TRUE); ca_clear(prod, ctx); ca_clear(upow, ctx); } if (0 && success) { printf("proved log relation!\n"); for (j = 0; j < num_logs; j++) { fmpz_print(rel + j); printf(" "); acb_printn(z + j, 10, 0); printf(" "); } printf("\n"); for (j = 0; j < num_logs; j++) { if (!fmpz_is_zero(rel + j) || 1) { fmpz_print(rel + j); flint_printf(" * log("); ca_print(CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, logs[j])), ctx); flint_printf(") "); } } flint_printf("\n"); } acb_clear(t); mag_clear(tm); return success; } slong ca_field_insert_log_relation(ca_field_t K, fmpz * rel, const slong * logs, slong index_i, slong index_pi, slong num_logs, slong num_logs_with_pi_i, ca_ctx_t ctx) { fmpz_mpoly_t poly; ulong * exp; slong which_removed; slong j, len; len = CA_FIELD_LENGTH(K); exp = flint_malloc(sizeof(ulong) * len); fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); which_removed = -1; for (j = 0; j < num_logs_with_pi_i; j++) { slong k; if (fmpz_is_zero(rel + j)) continue; if (which_removed == -1) which_removed = j; for (k = 0; k < len; k++) exp[k] = 0; /* 2 pi i */ if (j == num_logs) { exp[index_i] = 1; exp[index_pi] = 1; fmpz_mul_2exp(rel + j, rel + j, 1); } else { exp[logs[j]] = 1; } fmpz_mpoly_set_coeff_fmpz_ui(poly, rel + j, exp, CA_FIELD_MCTX(K, ctx)); } flint_free(exp); _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); return which_removed; } /* Find log relations. */ void ca_field_build_ideal_logs(ca_field_t K, ca_ctx_t ctx) { slong * logs; slong num_logs, num_logs_with_pi_i; slong prec; int have_pi, have_i, have_pi_i; slong index_pi, index_i; slong i, len; len = CA_FIELD_LENGTH(K); if (len < 2) return; num_logs = 0; logs = flint_malloc(sizeof(slong) * len); for (i = 0; i < len; i++) { if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, i)) == CA_Log) { logs[num_logs] = i; num_logs++; } } have_i = have_pi = 0; index_i = index_pi = -1; for (i = 0; i < len; i++) { if (CA_FIELD_EXT_ELEM(K, i) == CA_FIELD_EXT_ELEM(ctx->field_qq_i, 0)) { index_i = i; have_i = 1; break; } } for (i = 0; i < len; i++) { if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, i)) == CA_Pi) { index_pi = i; have_pi = 1; break; } } have_pi_i = have_pi && have_i; num_logs_with_pi_i = num_logs + have_pi_i; if (num_logs_with_pi_i >= 2) { fmpz_mat_t A; acb_ptr z; slong j, alloc; fmpz * rel; int found_relation = 0; slong which_removed = 0; slong row; prec = ctx->options[CA_OPT_LLL_PREC]; alloc = num_logs_with_pi_i; z = _acb_vec_init(alloc); for (j = 0; j < num_logs; j++) { /* todo: take advantage of cached enclosure */ ca_get_acb(z + j, CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, logs[j])), prec, ctx); acb_log(z + j, z + j, prec); } /* Add 2*pi*i as another logarithm */ if (have_pi_i) { acb_const_pi(z + num_logs, prec); acb_mul_onei(z + num_logs, z + num_logs); acb_mul_2exp_si(z + num_logs, z + num_logs, 1); } if (1) /* Find all integer relations at once. */ { fmpz_mat_init(A, 0, 0); acb_multi_lindep(A, z, num_logs_with_pi_i, 1, prec); for (row = 0; row < fmpz_mat_nrows(A); row++) { rel = A->rows[row]; if (!_fmpz_vec_is_zero(rel, num_logs_with_pi_i) && FLINT_ABS(_fmpz_vec_max_bits(rel, num_logs_with_pi_i)) <= 10) { if (ca_field_prove_log_relation(K, rel, z, logs, num_logs, num_logs_with_pi_i, prec, ctx)) { found_relation = 1; which_removed = ca_field_insert_log_relation(K, rel, logs, index_i, index_pi, num_logs, num_logs_with_pi_i, ctx); } } } fmpz_mat_clear(A); } else { rel = _fmpz_vec_init(alloc); while (num_logs_with_pi_i >= 2) { found_relation = 0; if (_qqbar_acb_lindep(rel, z, num_logs_with_pi_i, 1, prec)) { if (ca_field_prove_log_relation(K, rel, z, logs, num_logs, num_logs_with_pi_i, prec, ctx)) { found_relation = 1; which_removed = ca_field_insert_log_relation(K, rel, logs, index_i, index_pi, num_logs, num_logs_with_pi_i, ctx); } } if (!found_relation) break; for (j = which_removed; j < num_logs - 1; j++) logs[j] = logs[j + 1]; for (j = which_removed; j < num_logs_with_pi_i - 1; j++) acb_swap(z + j, z + j + 1); num_logs--; num_logs_with_pi_i--; } _fmpz_vec_clear(rel, alloc); } _acb_vec_clear(z, alloc); } flint_free(logs); } int ca_field_prove_multiplicative_relation(ca_field_t K, const fmpz * rel, acb_srcptr z, const slong * powers, slong num_powers, slong prec, ca_ctx_t ctx) { ca_t t, u; slong i; int success = 0; int all_qqbar = 1; ca_init(t, ctx); ca_init(u, ctx); if (ctx->options[CA_OPT_VERBOSE]) { flint_printf("Attempt to prove multiplicative relation:\n"); for (i = 0; i < num_powers + 1; i++) { flint_printf(" [ ^"); fmpz_print(rel + i); flint_printf("] "); if (i == num_powers) printf("(-1) "); else { ca_ext_print(CA_FIELD_EXT_ELEM(K, powers[i]), ctx); flint_printf(" "); } flint_printf("\n"); } flint_printf("\n"); } /* Special-case all qqbars; todo -- separate qqbars, exps; better algorithm */ for (i = 0; i < num_powers && all_qqbar; i++) { if (!fmpz_is_zero(rel + i)) { ca_ext_srcptr ext = CA_FIELD_EXT_ELEM(K, powers[i]); if (!CA_EXT_IS_QQBAR(ext)) all_qqbar = 0; } } if (all_qqbar) { qqbar_t a, b; qqbar_init(a); qqbar_init(b); qqbar_one(a); for (i = 0; i < num_powers; i++) { if (!fmpz_is_zero(rel + i)) { ca_ext_srcptr ext = CA_FIELD_EXT_ELEM(K, powers[i]); /* xxx: bogus limits */ if (!qqbar_pow_fmpz_checked(b, CA_EXT_QQBAR(ext), rel + i, ctx->options[CA_OPT_QQBAR_DEG_LIMIT], ctx->options[CA_OPT_PREC_LIMIT] * 10)) { success = 0; goto qqbar_end; } if (!qqbar_mul_checked(a, a, b, ctx->options[CA_OPT_QQBAR_DEG_LIMIT], ctx->options[CA_OPT_PREC_LIMIT] * 10)) { success = 0; goto qqbar_end; } } } /* (-1)^ */ if (fmpz_is_odd(rel + num_powers)) qqbar_neg(a, a); success = qqbar_is_one(a); qqbar_end: /* if (!success) { printf("qqbar failed!\n"); } */ qqbar_clear(a); qqbar_clear(b); } else { /* Todo: don't duplicate these computations */ for (i = 0; i < num_powers; i++) { if (!fmpz_is_zero(rel + i)) { ca_ext_srcptr ext = CA_FIELD_EXT_ELEM(K, powers[i]); if (CA_EXT_HEAD(ext) == CA_Sqrt) { ca_log(u, CA_EXT_FUNC_ARGS(ext), ctx); ca_div_ui(u, u, 2, ctx); } else if (CA_EXT_HEAD(ext) == CA_Pow) { ca_log(u, CA_EXT_FUNC_ARGS(ext), ctx); ca_mul(u, u, CA_EXT_FUNC_ARGS(ext) + 1, ctx); } else if (CA_EXT_HEAD(ext) == CA_Exp) { ca_set(u, CA_EXT_FUNC_ARGS(ext), ctx); } else if (CA_EXT_IS_QQBAR(ext)) { ca_set_qqbar(u, CA_EXT_QQBAR(ext), ctx); ca_log(u, u, ctx); } else { flint_abort(); } ca_mul_fmpz(u, u, rel + i, ctx); ca_add(t, t, u, ctx); } } if (!fmpz_is_zero(rel + num_powers)) { ca_pi_i(u, ctx); ca_mul_fmpz(u, u, rel + num_powers, ctx); ca_add(t, t, u, ctx); } success = (ca_check_is_zero(t, ctx) == T_TRUE); } if (ctx->options[CA_OPT_VERBOSE]) { flint_printf(" Success = %d\n\n", success); } ca_clear(t, ctx); ca_clear(u, ctx); return success; } slong ca_field_insert_multiplicative_relation(ca_field_t K, fmpz * rel, const slong * powers, slong num_powers, ca_ctx_t ctx) { /* x^a y^b +/- z^d w^e = 0 */ fmpz_mpoly_t poly; ulong * exp1; ulong * exp2; int neg; slong len, j, which_removed; len = CA_FIELD_LENGTH(K); which_removed = -1; fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); exp1 = flint_calloc(len, sizeof(ulong)); exp2 = flint_calloc(len, sizeof(ulong)); neg = fmpz_is_odd(rel + num_powers); for (j = 0; j < num_powers; j++) { if (fmpz_is_zero(rel + j)) continue; if (which_removed == -1) which_removed = j; if (fmpz_sgn(rel + j) > 0) exp1[powers[j]] = rel[j]; else exp2[powers[j]] = -rel[j]; } /* todo: normalise sign? */ fmpz_mpoly_set_coeff_si_ui(poly, 1, exp1, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_set_coeff_si_ui(poly, neg ? 1 : -1, exp2, CA_FIELD_MCTX(K, ctx)); flint_free(exp1); flint_free(exp2); _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); return which_removed; } /* Find relations involving exponentials, powers and roots. */ /* Todo: more special cases (including roots of unity) */ void ca_field_build_ideal_multiplicative(ca_field_t K, ca_ctx_t ctx) { slong i, len; slong * powers; slong num_powers; slong prec; len = CA_FIELD_LENGTH(K); if (len == 0) return; num_powers = 0; powers = flint_malloc(sizeof(slong) * len); for (i = 0; i < len; i++) { if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, i)) == CA_Sqrt) { powers[num_powers] = i; num_powers++; } else if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, i)) == CA_Pow) { powers[num_powers] = i; num_powers++; } else if (CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, i)) == CA_Exp) { powers[num_powers] = i; num_powers++; } else if (CA_EXT_IS_QQBAR(CA_FIELD_EXT_ELEM(K, i))) { powers[num_powers] = i; num_powers++; } } if (num_powers >= 1) { acb_ptr z; fmpz * rel; slong alloc, j; int found_relation = 0; slong which_removed = 0; fmpz_mat_t A; slong row; prec = ctx->options[CA_OPT_LLL_PREC]; alloc = num_powers + 1; z = _acb_vec_init(alloc); for (i = 0; i < num_powers; i++) { ca_ext_srcptr ext = CA_FIELD_EXT_ELEM(K, powers[i]); if (CA_EXT_HEAD(ext) == CA_Sqrt) { ca_get_acb(z + i, CA_EXT_FUNC_ARGS(ext), prec, ctx); acb_log(z + i, z + i, prec); acb_mul_2exp_si(z + i, z + i, -1); } else if (CA_EXT_HEAD(ext) == CA_Pow) { ca_get_acb(z + i, CA_EXT_FUNC_ARGS(ext), prec, ctx); acb_log(z + i, z + i, prec); ca_get_acb(z + i + 1, CA_EXT_FUNC_ARGS(ext) + 1, prec, ctx); /* xxx */ acb_mul(z + i, z + i, z + i + 1, prec); } else if (CA_EXT_HEAD(ext) == CA_Exp) { ca_get_acb(z + i, CA_EXT_FUNC_ARGS(ext), prec, ctx); } else if (CA_EXT_IS_QQBAR(ext)) { qqbar_get_acb(z + i, CA_EXT_QQBAR(ext), prec); acb_log(z + i, z + i, prec); } else { flint_abort(); } } /* todo: exp(pi i) = -1 --- look for other roots of unity! */ /* todo: what else to include -- log(2), log(3), log(5) ? */ acb_const_pi(z + num_powers, prec); acb_mul_onei(z + num_powers, z + num_powers); /* todo: verify that logs are not evaluated at zero... */ if (1) /* Find all integer relations at once. */ { fmpz_mat_init(A, 0, 0); acb_multi_lindep(A, z, num_powers + 1, 1, prec); for (row = 0; row < fmpz_mat_nrows(A); row++) { rel = A->rows[row]; if (!_fmpz_vec_is_zero(rel, num_powers + 1) && FLINT_ABS(_fmpz_vec_max_bits(rel, num_powers + 1)) <= 10) { if (ca_field_prove_multiplicative_relation(K, rel, z, powers, num_powers, prec, ctx)) { ca_field_insert_multiplicative_relation(K, rel, powers, num_powers, ctx); } } } fmpz_mat_clear(A); } else { rel = _fmpz_vec_init(alloc); while (num_powers >= 1) { found_relation = 0; if (_qqbar_acb_lindep(rel, z, num_powers + 1, 1, prec) && FLINT_ABS(_fmpz_vec_max_bits(rel, num_powers + 1)) <= 10) { if (!_fmpz_vec_is_zero(rel, num_powers + 1) && FLINT_ABS(_fmpz_vec_max_bits(rel, num_powers + 1)) <= 10) { if (ca_field_prove_multiplicative_relation(K, rel, z, powers, num_powers, prec, ctx)) { ca_field_insert_multiplicative_relation(K, rel, powers, num_powers, ctx); } } } if (!found_relation) break; for (j = which_removed; j < num_powers - 1; j++) powers[j] = powers[j + 1]; for (j = which_removed; j < num_powers; j++) acb_swap(z + j, z + j + 1); num_powers--; } _fmpz_vec_clear(rel, alloc); } _acb_vec_clear(z, alloc); } flint_free(powers); } /* todo: move to utils */ void fmpz_mpoly_set_coeff_si_x(fmpz_mpoly_t poly, slong c, slong x_var, slong x_exp, const fmpz_mpoly_ctx_t ctx); void ca_field_build_ideal(ca_field_t K, ca_ctx_t ctx) { slong i, len; len = CA_FIELD_LENGTH(K); if (len <= 0) return; if (len == 1 && CA_EXT_IS_QQBAR(CA_FIELD_EXT_ELEM(K, 0))) return; /* Find direct algebraic relations. */ if (len >= 2) { slong deg, vieta_limit; vieta_limit = ctx->options[CA_OPT_VIETA_LIMIT]; for (i = 0; vieta_limit > 0 && i < len; i++) { ca_ext_struct * x = CA_FIELD_EXT_ELEM(K, i); /* If all conjugates of an algebraic number are present, add Vieta's formulas. */ if (CA_EXT_IS_QQBAR(x) && ((deg = qqbar_degree(CA_EXT_QQBAR(x))) <= vieta_limit)) { slong j, num_conjugates; num_conjugates = 0; for (j = i + 1; j < len; j++) { ca_ext_struct * y = CA_FIELD_EXT_ELEM(K, j); if (CA_EXT_IS_QQBAR(y) && fmpz_poly_equal(QQBAR_POLY(CA_EXT_QQBAR(x)), QQBAR_POLY(CA_EXT_QQBAR(y)))) num_conjugates++; else break; } if (num_conjugates + 1 == deg) { fmpz_mpoly_t r; slong k; slong * vars; ulong binom; /* an * (x1 + x2 + ... + xn) + a[n-1] = 0, etc. */ /* todo: remove coefficient GCD */ vars = flint_malloc(deg * sizeof(slong)); for (k = 0; k < deg; k++) vars[k] = i + k; binom = 1; for (k = 1; k <= deg; k++) { binom = binom * (deg - k + 1) / k; /* alternative way to define a cutoff: if (binom > (ulong) vieta_limit) break; */ fmpz_mpoly_init(r, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_symmetric_gens(r, k, vars, deg, CA_FIELD_MCTX(K, ctx)); /* todo: cancel gcd between coefficients */ fmpz_mpoly_scalar_mul_fmpz(r, r, QQBAR_COEFFS(CA_EXT_QQBAR(x)) + deg, CA_FIELD_MCTX(K, ctx)); if (k % 2 == 1) fmpz_mpoly_add_fmpz(r, r, QQBAR_COEFFS(CA_EXT_QQBAR(x)) + deg - k, CA_FIELD_MCTX(K, ctx)); else fmpz_mpoly_sub_fmpz(r, r, QQBAR_COEFFS(CA_EXT_QQBAR(x)) + deg - k, CA_FIELD_MCTX(K, ctx)); _ca_field_ideal_insert_clear_mpoly(K, r, CA_FIELD_MCTX(K, ctx), ctx); } flint_free(vars); } i += num_conjugates; } } for (i = 0; i < len; i++) { slong a, b; ca_ext_struct * x = CA_FIELD_EXT_ELEM(K, i); /* Absolute annihilating polynomial for number field */ if (CA_EXT_IS_QQBAR(x)) { fmpz_mpoly_t poly; fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_set_gen_fmpz_poly(poly, i, QQBAR_POLY(CA_EXT_QQBAR(x)), CA_FIELD_MCTX(K, ctx)); _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); continue; } /* x = sqrt(t) -> x^2 - t = 0 */ /* x = t^(a/b) -> x^b - t^a = 0 */ /* A relation will only be added if t can be expressed in the present field. */ if (ext_as_pow_pq(&a, &b, x, ctx)) { ca_srcptr t; ca_field_struct * L; /* Field of t */ slong L_len; slong * tgen_map; slong j, k; int success; t = CA_EXT_FUNC_ARGS(x); if (CA_IS_SPECIAL(t)) flint_abort(); L = CA_FIELD(t, ctx); L_len = CA_FIELD_LENGTH(L); success = 1; tgen_map = flint_malloc(L_len * sizeof(slong)); for (j = 0; j < L_len; j++) { for (k = 0; k < len; k++) { if (CA_FIELD_EXT_ELEM(L, j) == CA_FIELD_EXT_ELEM(K, k)) { tgen_map[j] = k; break; } if (k == len - 1) success = 0; } } if (success) { /* u^2 - p/q --> q u^2 - p */ /* u^b - (p/q)^a --> q^a u^b - p^a */ fmpz_mpoly_t p, q, u2; fmpz_mpoly_init(p, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_init(q, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_init(u2, CA_FIELD_MCTX(K, ctx)); if (L_len == 0) /* todo: use CA_IS_QQ when renamed */ { fmpz_mpoly_set_fmpz(p, CA_FMPQ_NUMREF(t), CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_set_fmpz(q, CA_FMPQ_DENREF(t), CA_FIELD_MCTX(K, ctx)); } else if (CA_FIELD_IS_NF(L)) { fmpz_poly_t pol; fmpz_t den; _nf_elem_get_fmpz_poly_den_shallow(pol, den, CA_NF_ELEM(t), CA_FIELD_NF(L)); fmpz_mpoly_set_gen_fmpz_poly(p, tgen_map[0], pol, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_set_fmpz(q, den, CA_FIELD_MCTX(K, ctx)); } else { fmpz_mpoly_compose_fmpz_mpoly_gen(p, fmpz_mpoly_q_numref(CA_MPOLY_Q(t)), tgen_map, CA_FIELD_MCTX(L, ctx), CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_compose_fmpz_mpoly_gen(q, fmpz_mpoly_q_denref(CA_MPOLY_Q(t)), tgen_map, CA_FIELD_MCTX(L, ctx), CA_FIELD_MCTX(K, ctx)); } fmpz_mpoly_gen(u2, i, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_pow_ui(u2, u2, b, CA_FIELD_MCTX(K, ctx)); if (a < 0) { fmpz_mpoly_swap(p, q, CA_FIELD_MCTX(K, ctx)); a = -a; } if (a != 1) fmpz_mpoly_pow_ui(q, q, a, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_mul(u2, u2, q, CA_FIELD_MCTX(K, ctx)); if (a != 1) fmpz_mpoly_pow_ui(p, p, a, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_sub(u2, u2, p, CA_FIELD_MCTX(K, ctx)); _ca_field_ideal_insert_clear_mpoly(K, u2, CA_FIELD_MCTX(K, ctx), ctx); /* u2 does not need to be cleared */ fmpz_mpoly_clear(p, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_clear(q, CA_FIELD_MCTX(K, ctx)); } flint_free(tgen_map); } } } ca_field_build_ideal_logs(K, ctx); ca_field_build_ideal_multiplicative(K, ctx); /* ca_field_build_ideal_sin_cos(K, ctx); */ ca_field_build_ideal_erf(K, ctx); ca_field_build_ideal_gamma(K, ctx); if (ctx->options[CA_OPT_USE_GROEBNER]) { slong i; int want_groebner; want_groebner = 1; for (i = 0; i < CA_FIELD_IDEAL_LENGTH(K); i++) { if (fmpz_mpoly_total_degree_si(CA_FIELD_IDEAL_ELEM(K, i), CA_FIELD_MCTX(K, ctx)) > ctx->options[CA_OPT_QQBAR_DEG_LIMIT]) { want_groebner = 0; break; } } if (want_groebner && CA_FIELD_IDEAL(K)->length > 0) { if (ctx->options[CA_OPT_VERBOSE]) { flint_printf("Attempt to compute Groebner basis for:\n "); fmpz_mpoly_vec_print(CA_FIELD_IDEAL(K), CA_FIELD_MCTX(K, ctx)); flint_printf("\n\n"); } /* Consider autoreduction as a preprocessing step. This is not necessarily a win, because the vector is usually nearly autoreduced by construction. */ if (0) { slong before, after; before = CA_FIELD_IDEAL_LENGTH(K); fmpz_mpoly_vec_autoreduction(CA_FIELD_IDEAL(K), CA_FIELD_IDEAL(K), CA_FIELD_MCTX(K, ctx)); after = CA_FIELD_IDEAL_LENGTH(K); if (before > 4) flint_printf("before, after: %wd %wd\n", before, after); } if (fmpz_mpoly_buchberger_naive_with_limits(CA_FIELD_IDEAL(K), CA_FIELD_IDEAL(K), ctx->options[CA_OPT_GROEBNER_LENGTH_LIMIT], ctx->options[CA_OPT_GROEBNER_POLY_LENGTH_LIMIT], ctx->options[CA_OPT_GROEBNER_POLY_BITS_LIMIT], CA_FIELD_MCTX(K, ctx))) { fmpz_mpoly_vec_autoreduction_groebner(CA_FIELD_IDEAL(K), CA_FIELD_IDEAL(K), CA_FIELD_MCTX(K, ctx)); if (ctx->options[CA_OPT_VERBOSE]) { flint_printf("Computed Groebner basis:\n "); fmpz_mpoly_vec_print(CA_FIELD_IDEAL(K), CA_FIELD_MCTX(K, ctx)); flint_printf("\n\n"); } } else { if (ctx->options[CA_OPT_VERBOSE]) { flint_printf("WARNING: Failed to compute a Groebner basis\n"); flint_printf("Current ideal:\n "); fmpz_mpoly_vec_print(CA_FIELD_IDEAL(K), CA_FIELD_MCTX(K, ctx)); flint_printf("\n\n"); } } } } } calcium-0.4.1/ca_field/build_ideal_erf.c000066400000000000000000000311411407704557200201270ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" void _ca_field_ideal_insert_clear_mpoly(ca_field_t K, fmpz_mpoly_t poly, fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx); /* todo: optimize */ truth_t ca_check_equal_neg(const ca_t x, const ca_t y, ca_ctx_t ctx) { ca_t t; truth_t res; ca_init(t, ctx); ca_neg(t, y, ctx); res = ca_check_equal(x, t, ctx); ca_clear(t, ctx); return res; } /* set a*x_a + b*x_b + c */ void fmpz_mpoly_set_linear_three_term_si(fmpz_mpoly_t poly, slong a, slong xa, slong b, slong xb, slong c, const fmpz_mpoly_ctx_t ctx) { ulong * exp; exp = flint_calloc(ctx->minfo->nvars, sizeof(ulong)); if (xa == xb) { flint_printf("fmpz_mpoly_set_linear_three_term_si\n"); flint_abort(); } fmpz_mpoly_set_si(poly, c, ctx); exp[xa] = 1; fmpz_mpoly_set_coeff_si_ui(poly, a, exp, ctx); exp[xa] = 0; exp[xb] = 1; fmpz_mpoly_set_coeff_si_ui(poly, b, exp, ctx); flint_free(exp); } /* set a*x_a*x_a2 + b*x_b + c */ void fmpz_mpoly_set_linear2_three_term_si(fmpz_mpoly_t poly, slong a, slong xa, slong xa2, slong b, slong xb, slong c, const fmpz_mpoly_ctx_t ctx) { ulong * exp; exp = flint_calloc(ctx->minfo->nvars, sizeof(ulong)); if (xa == xb || xa == xa2) { flint_printf("fmpz_mpoly_set_linear2_three_term_si\n"); flint_abort(); } fmpz_mpoly_set_si(poly, c, ctx); exp[xa] = 1; exp[xa2] = 1; fmpz_mpoly_set_coeff_si_ui(poly, a, exp, ctx); exp[xa] = 0; exp[xa2] = 0; exp[xb] = 1; fmpz_mpoly_set_coeff_si_ui(poly, b, exp, ctx); flint_free(exp); } /* Set the term c * x_var^x_exp */ void fmpz_mpoly_set_coeff_si_x(fmpz_mpoly_t poly, slong c, slong x_var, slong x_exp, const fmpz_mpoly_ctx_t ctx) { ulong * exp; slong i, len; TMP_INIT; len = ctx->minfo->nvars; TMP_START; exp = TMP_ALLOC(len * sizeof(ulong)); for (i = 0; i < len; i++) exp[i] = 0; exp[x_var] = x_exp; fmpz_mpoly_set_coeff_si_ui(poly, c, exp, ctx); TMP_END; } void fmpz_mpoly_set_coeff_si_xy(fmpz_mpoly_t poly, slong c, slong x_var, ulong x_exp, slong y_var, ulong y_exp, const fmpz_mpoly_ctx_t ctx) { ulong * exp; slong i, len; TMP_INIT; len = ctx->minfo->nvars; TMP_START; exp = TMP_ALLOC(len * sizeof(ulong)); for (i = 0; i < len; i++) exp[i] = 0; exp[x_var] = x_exp; exp[y_var] = y_exp; fmpz_mpoly_set_coeff_si_ui(poly, c, exp, ctx); TMP_END; } static void ideal_mixed_erfi(ca_field_t K, slong i, slong j, int have_i, slong index_i, ca_ctx_t ctx) { calcium_func_code Fi; ca_t ix; ca_ptr x, y; fmpz_mpoly_t poly; const fmpz_mpoly_ctx_struct * mctx = CA_FIELD_MCTX(K, ctx); x = CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, i)); y = CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, j)); Fi = CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, i)); ca_init(ix, ctx); ca_i(ix, ctx); ca_mul(ix, ix, x, ctx); if (ca_check_equal(ix, y, ctx) == T_TRUE) { if (have_i) { fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); if (Fi == CA_Erf) { /* erf(x) + i*erfi(i*x) */ fmpz_mpoly_set_coeff_si_x(poly, 1, i, 1, mctx); fmpz_mpoly_set_coeff_si_xy(poly, 1, j, 1, index_i, 1, mctx); } else { /* erfc(x) - i*erfi(i*x) - 1 */ fmpz_mpoly_set_si(poly, -1, mctx); fmpz_mpoly_set_coeff_si_x(poly, 1, i, 1, mctx); fmpz_mpoly_set_coeff_si_xy(poly, -1, j, 1, index_i, 1, mctx); } _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); } if (have_i) { fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); if (Fi == CA_Erf) { /* i*erf(x) - erfi(i*x) */ fmpz_mpoly_set_coeff_si_xy(poly, 1, i, 1, index_i, 1, mctx); fmpz_mpoly_set_coeff_si_x(poly, -1, j, 1, mctx); } else { /* i*erfc(x) + erfi(i*x) - i */ fmpz_mpoly_set_coeff_si_xy(poly, 1, i, 1, index_i, 1, mctx); fmpz_mpoly_set_coeff_si_x(poly, 1, j, 1, mctx); fmpz_mpoly_set_coeff_si_x(poly, -1, index_i, 1, mctx); } _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); } fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); if (Fi == CA_Erf) { /* erf(x)^2 + erfi(i*x)^2 = 0 */ fmpz_mpoly_set_coeff_si_x(poly, 1, i, 2, mctx); fmpz_mpoly_set_coeff_si_x(poly, 1, j, 2, mctx); } else { /* erfc(x)^2 - 2*erfc(x) + erfi(i*x)**2 + 1 */ fmpz_mpoly_set_si(poly, 1, mctx); fmpz_mpoly_set_coeff_si_x(poly, 1, i, 2, mctx); fmpz_mpoly_set_coeff_si_x(poly, -2, i, 1, mctx); fmpz_mpoly_set_coeff_si_x(poly, 1, j, 2, mctx); } _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); } else if (ca_check_equal_neg(ix, y, ctx) == T_TRUE) { if (have_i) { fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); if (Fi == CA_Erf) { /* erf(x) - i*erfi(-i*x) */ fmpz_mpoly_set_coeff_si_x(poly, 1, i, 1, mctx); fmpz_mpoly_set_coeff_si_xy(poly, -1, j, 1, index_i, 1, mctx); } else { /* erfc(x) + i*erfi(-i*x) - 1 */ fmpz_mpoly_set_si(poly, -1, mctx); fmpz_mpoly_set_coeff_si_x(poly, 1, i, 1, mctx); fmpz_mpoly_set_coeff_si_xy(poly, 1, j, 1, index_i, 1, mctx); } _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); } if (have_i) { fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); if (Fi == CA_Erf) { /* i*erf(x) + erfi(-i*x) */ fmpz_mpoly_set_coeff_si_xy(poly, 1, i, 1, index_i, 1, mctx); fmpz_mpoly_set_coeff_si_x(poly, 1, j, 1, mctx); } else { /* i*erfc(x) - erfi(-i*x) - i */ fmpz_mpoly_set_coeff_si_xy(poly, 1, i, 1, index_i, 1, mctx); fmpz_mpoly_set_coeff_si_x(poly, -1, j, 1, mctx); fmpz_mpoly_set_coeff_si_x(poly, -1, index_i, 1, mctx); } _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); } fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); if (Fi == CA_Erf) { /* erf(x)^2 + erfi(-i*x)^2 = 0 */ fmpz_mpoly_set_coeff_si_x(poly, 1, i, 2, mctx); fmpz_mpoly_set_coeff_si_x(poly, 1, j, 2, mctx); } else { /* erfc(x)^2 - 2*erfc(x) + erfi(-i*x)**2 + 1 */ fmpz_mpoly_set_si(poly, 1, mctx); fmpz_mpoly_set_coeff_si_x(poly, 1, i, 2, mctx); fmpz_mpoly_set_coeff_si_x(poly, -2, i, 1, mctx); fmpz_mpoly_set_coeff_si_x(poly, 1, j, 2, mctx); } _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); } ca_clear(ix, ctx); } /* erf(x) - erf(x) = 0 erfc(x) - erfc(x) = 0 erfi(x) - erfi(x) = 0 erf(x) + erfc(x) - 1 = 0 erf(x) + erf(-x) = 0 erfc(x) + erfc(-x) - 2 = 0 erfi(x) + erfi(-x) = 0 erf(x) - erfc(-x) + 1 = 0 erfc(x) - erf(-x) - 1 = 0 erf(x) + i*erfi(i*x) = 0 erf(x) - i*erfi(-i*x) = 0 erfc(x) - i*erfi(i*x) - 1 = 0 erfc(x) + i*erfi(-i*x) - 1 = 0 */ void ca_field_build_ideal_erf(ca_field_t K, ca_ctx_t ctx) { slong i, j, len, num_erf, index_i; calcium_func_code Fi, Fj; int have_i; len = CA_FIELD_LENGTH(K); if (len < 2) return; index_i = 0; have_i = 0; num_erf = 0; for (i = 0; i < len; i++) { Fi = CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, i)); if (Fi == CA_Erf || Fi == CA_Erfc || Fi == CA_Erfi) { num_erf++; } else if (CA_FIELD_EXT_ELEM(K, i) == CA_FIELD_EXT_ELEM(ctx->field_qq_i, 0)) { have_i = 1; index_i = i; } } if (num_erf >= 2) { for (i = 0; i < len; i++) { Fi = CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, i)); if (Fi == CA_Erf || Fi == CA_Erfc || Fi == CA_Erfi) { for (j = i + 1; j < len; j++) { Fj = CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, j)); if (Fj == CA_Erf || Fj == CA_Erfc || Fj == CA_Erfi) { if ((Fj == CA_Erfi && (Fi == CA_Erf || Fi == CA_Erfc))) { ideal_mixed_erfi(K, i, j, have_i, index_i, ctx); continue; } if ((Fi == CA_Erfi && (Fj == CA_Erf || Fj == CA_Erfc))) { ideal_mixed_erfi(K, j, i, have_i, index_i, ctx); continue; } if (Fi == Fj || (Fi == CA_Erf && Fj == CA_Erfc) || (Fi == CA_Erfc && Fj == CA_Erf)) { if (ca_check_equal(CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, i)), CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, j)), ctx) == T_TRUE) { /* erf(x) - erf(x) = 0 erfc(x) - erfc(x) = 0 erfi(x) - erfi(x) = 0 erf(x) + erfc(x) - 1 = 0 */ fmpz_mpoly_t poly; fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); if (Fi == Fj) fmpz_mpoly_set_linear_three_term_si(poly, 1, i, -1, j, 0, CA_FIELD_MCTX(K, ctx)); else fmpz_mpoly_set_linear_three_term_si(poly, 1, i, 1, j, -1, CA_FIELD_MCTX(K, ctx)); _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); } else if (ca_check_equal_neg(CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, i)), CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, j)), ctx) == T_TRUE) { /* erf(x) + erf(-x) = 0 erfc(x) + erfc(-x) - 2 = 0 erfi(x) + erfi(-x) = 0 erf(x) - erfc(-x) + 1 = 0 erfc(x) - erf(-x) - 1 = 0 */ fmpz_mpoly_t poly; fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); if (Fi == Fj) { if (Fi == CA_Erfc) fmpz_mpoly_set_linear_three_term_si(poly, 1, i, 1, j, -2, CA_FIELD_MCTX(K, ctx)); else fmpz_mpoly_set_linear_three_term_si(poly, 1, i, 1, j, 0, CA_FIELD_MCTX(K, ctx)); } else { if (Fi == CA_Erf) fmpz_mpoly_set_linear_three_term_si(poly, 1, i, -1, j, 1, CA_FIELD_MCTX(K, ctx)); else fmpz_mpoly_set_linear_three_term_si(poly, 1, i, -1, j, -1, CA_FIELD_MCTX(K, ctx)); } _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); } } } } } } } } calcium-0.4.1/ca_field/build_ideal_gamma.c000066400000000000000000000201321407704557200204330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" #include "utils_flint.h" void _ca_field_ideal_insert_clear_mpoly(ca_field_t K, fmpz_mpoly_t poly, fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx); void _nf_elem_get_fmpz_poly_den_shallow(fmpz_poly_t pol, fmpz_t den, const nf_elem_t a, const nf_t nf); void fmpz_mpoly_set_coeff_si_x(fmpz_mpoly_t poly, slong c, slong x_var, slong x_exp, const fmpz_mpoly_ctx_t ctx); void ca_field_build_ideal_gamma(ca_field_t K, ca_ctx_t ctx) { calcium_func_code Fi, Fj; slong i, j, len, num_gamma; len = CA_FIELD_LENGTH(K); if (len < 2) return; num_gamma = 0; for (i = 0; i < len; i++) { Fi = CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, i)); if (Fi == CA_Gamma) { num_gamma++; } } if (num_gamma < 2) return; for (i = 0; i < len; i++) { Fi = CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, i)); if (Fi == CA_Gamma) { for (j = i + 1; j < len; j++) { Fj = CA_EXT_HEAD(CA_FIELD_EXT_ELEM(K, j)); if (Fj == CA_Gamma) { ca_ptr xi, xj; ca_t t, u; fmpz_t N; slong n; xi = CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, i)); xj = CA_EXT_FUNC_ARGS(CA_FIELD_EXT_ELEM(K, j)); ca_init(t, ctx); ca_init(u, ctx); fmpz_init(N); ca_sub(t, xi, xj, ctx); if (ca_get_fmpz(N, t, ctx) && fmpz_cmp_si(N, -10) >= 0 && fmpz_cmp_si(N, 10) <= 0) { n = fmpz_get_si(N); if (n == 0) { fmpz_mpoly_t poly; fmpz_mpoly_init(poly, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_set_coeff_si_x(poly, 1, i, 1, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_set_coeff_si_x(poly, -1, j, 1, CA_FIELD_MCTX(K, ctx)); _ca_field_ideal_insert_clear_mpoly(K, poly, CA_FIELD_MCTX(K, ctx), ctx); } else { ca_field_struct * L; /* Field of t */ slong L_len; slong * tgen_map; slong k, m; int success; /* gamma(x+3) = (x+2)*(x+1)*x * gamma(x) */ /* (x-1)*(x-2)*(x-3) * gamma(x-3) = gamma(x) */ if (n > 0) { ca_set(t, xj, ctx); for (k = 1; k < n; k++) { ca_add_ui(u, xj, k, ctx); ca_mul(t, t, u, ctx); } } else { ca_sub_ui(t, xj, 1, ctx); for (k = 1; k < (-n); k++) { ca_sub_ui(u, xj, k + 1, ctx); ca_mul(t, t, u, ctx); } } L = CA_FIELD(t, ctx); L_len = CA_FIELD_LENGTH(L); success = 1; tgen_map = flint_malloc(L_len * sizeof(slong)); for (m = 0; m < L_len; m++) { for (k = 0; k < len; k++) { if (CA_FIELD_EXT_ELEM(L, m) == CA_FIELD_EXT_ELEM(K, k)) { tgen_map[m] = k; break; } if (k == len - 1) success = 0; } } if (success) { fmpz_mpoly_t p, q, pxi, pxj; fmpz_mpoly_init(p, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_init(q, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_init(pxi, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_init(pxj, CA_FIELD_MCTX(K, ctx)); /* todo: factor out */ if (L_len == 0) { fmpz_mpoly_set_fmpz(p, CA_FMPQ_NUMREF(t), CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_set_fmpz(q, CA_FMPQ_DENREF(t), CA_FIELD_MCTX(K, ctx)); } else if (CA_FIELD_IS_NF(L)) { fmpz_poly_t pol; fmpz_t den; _nf_elem_get_fmpz_poly_den_shallow(pol, den, CA_NF_ELEM(t), CA_FIELD_NF(L)); fmpz_mpoly_set_gen_fmpz_poly(p, tgen_map[0], pol, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_set_fmpz(q, den, CA_FIELD_MCTX(K, ctx)); } else { fmpz_mpoly_compose_fmpz_mpoly_gen(p, fmpz_mpoly_q_numref(CA_MPOLY_Q(t)), tgen_map, CA_FIELD_MCTX(L, ctx), CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_compose_fmpz_mpoly_gen(q, fmpz_mpoly_q_denref(CA_MPOLY_Q(t)), tgen_map, CA_FIELD_MCTX(L, ctx), CA_FIELD_MCTX(K, ctx)); } fmpz_mpoly_gen(pxi, i, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_gen(pxj, j, CA_FIELD_MCTX(K, ctx)); if (n < 0) fmpz_mpoly_swap(p, q, CA_FIELD_MCTX(K, ctx)); /* pxi = (p/q) * pxj */ /* q * pxi - p * pxj = 0*/ fmpz_mpoly_mul(q, q, pxi, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_mul(p, p, pxj, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_sub(q, q, p, CA_FIELD_MCTX(K, ctx)); _ca_field_ideal_insert_clear_mpoly(K, q, CA_FIELD_MCTX(K, ctx), ctx); fmpz_mpoly_clear(p, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_clear(pxi, CA_FIELD_MCTX(K, ctx)); fmpz_mpoly_clear(pxj, CA_FIELD_MCTX(K, ctx)); } flint_free(tgen_map); } } ca_clear(t, ctx); ca_clear(u, ctx); fmpz_clear(N); } } } } } calcium-0.4.1/ca_field/cache_clear.c000066400000000000000000000013221407704557200172450ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_field.h" void ca_field_cache_clear(ca_field_cache_t cache, ca_ctx_t ctx) { slong i; for (i = 0; i < cache->length; i++) ca_field_clear(cache->items[i], ctx); for (i = 0; i < cache->alloc; i++) flint_free(cache->items[i]); flint_free(cache->items); flint_free(cache->hash_table); } calcium-0.4.1/ca_field/cache_init.c000066400000000000000000000014231407704557200171240ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_field.h" #define INITIAL_HASH_SIZE 16 void ca_field_cache_init(ca_field_cache_t cache, ca_ctx_t ctx) { slong i; cache->items = NULL; cache->length = 0; cache->alloc = 0; cache->hash_size = INITIAL_HASH_SIZE; cache->hash_table = flint_malloc(sizeof(slong) * INITIAL_HASH_SIZE); for (i = 0; i < INITIAL_HASH_SIZE; i++) cache->hash_table[i] = -1; } calcium-0.4.1/ca_field/cache_insert.c000066400000000000000000000110521407704557200174640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_ext.h" #include "ca_field.h" ca_field_ptr ca_field_cache_lookup_qqbar(ca_field_cache_t cache, const qqbar_t x, ca_ctx_t ctx) { ulong xhash; ca_field_ptr K; slong i, loc; xhash = qqbar_hash(x); loc = xhash % ((ulong) cache->hash_size); for (i = 0; i < cache->hash_size; i++) { /* not found */ if (cache->hash_table[loc] == -1) return NULL; K = cache->items[cache->hash_table[loc]]; /* found */ if (CA_FIELD_IS_NF(K) && qqbar_equal(x, CA_FIELD_NF_QQBAR(K))) return K; loc++; if (loc == cache->hash_size) loc = 0; } /* cannot happen */ flint_abort(); } ulong _ca_field_hash(ca_ext_struct ** ext, slong len, ca_ctx_t ctx) { ulong s; slong i; s = 0; for (i = 0; i < len; i++) s = s * CA_FIELD_HASH_C + CA_EXT_HASH(ext[i]); return s; } ulong ca_field_hash(const ca_field_t K, ca_ctx_t ctx) { return _ca_field_hash(K->ext, K->length, ctx); } static int _ca_field_equal_ext(const ca_field_t K, ca_ext_struct ** x, slong len, ca_ctx_t ctx) { slong i; if (len != CA_FIELD_LENGTH(K)) return 0; for (i = 0; i < len; i++) if (CA_FIELD_EXT_ELEM(K, i) != x[i]) return 0; return 1; } void ca_field_init_set_ext(ca_field_t K, ca_ext_struct ** ext, slong len, ca_ctx_t ctx) { if (len == 0) { ca_field_init_qq(K, ctx); } else if (len == 1 && CA_EXT_IS_QQBAR(ext[0])) { CA_FIELD_LENGTH(K) = 1; CA_FIELD_EXT(K) = flint_malloc(sizeof(ca_ext_ptr)); CA_FIELD_EXT_ELEM(K, 0) = ext[0]; CA_FIELD_IDEAL_P(K) = NULL; CA_FIELD_IDEAL_LENGTH(K) = -1; CA_FIELD_IDEAL_ALLOC(K) = 0; CA_FIELD_HASH(K) = CA_EXT_HASH(ext[0]); } else { slong i; ca_field_init_multi(K, len, ctx); for (i = 0; i < len; i++) ca_field_set_ext(K, i, ext[i], ctx); } } ca_field_ptr ca_field_cache_insert_ext(ca_field_cache_t cache, ca_ext_struct ** x, slong length, ca_ctx_t ctx) { ulong xhash; slong i, loc; xhash = _ca_field_hash(x, length, ctx); /* make room for inserting entry if needed */ if (cache->length == cache->alloc) { slong new_alloc; new_alloc = FLINT_MAX(1, cache->alloc * 2); cache->items = flint_realloc(cache->items, sizeof(ca_field_struct *) * new_alloc); for (i = cache->alloc; i < new_alloc; i++) cache->items[i] = flint_malloc(sizeof(ca_field_struct)); cache->alloc = new_alloc; } /* rehash if needed */ if (cache->length >= 0.5 * cache->hash_size) { slong new_size, j; slong * new_table; ulong thash; new_size = cache->hash_size * 2; new_table = flint_malloc(sizeof(slong) * new_size); for (i = 0; i < new_size; i++) new_table[i] = -1; for (i = 0; i < cache->length; i++) { thash = ca_field_hash(cache->items[i], ctx); j = thash % new_size; while (new_table[j] != -1) { j++; if (j == new_size) j = 0; } new_table[j] = i; } flint_free(cache->hash_table); cache->hash_size = new_size; cache->hash_table = new_table; } loc = xhash % ((ulong) cache->hash_size); for (i = 0; i < cache->hash_size; i++) { /* not found, so insert */ if (cache->hash_table[loc] == -1) { ca_field_ptr res; ca_field_init_set_ext(cache->items[cache->length], x, length, ctx); cache->hash_table[loc] = cache->length; cache->length++; /* save pointer; build_ideal can resize the cache */ res = cache->items[cache->length - 1]; ca_field_build_ideal(res, ctx); return res; } /* found */ if (_ca_field_equal_ext(cache->items[cache->hash_table[loc]], x, length, ctx)) return cache->items[cache->hash_table[loc]]; loc++; if (loc == cache->hash_size) loc = 0; } /* cannot happen */ flint_abort(); } calcium-0.4.1/ca_field/clear.c000066400000000000000000000012751407704557200161310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_field.h" void ca_field_clear(ca_field_t K, ca_ctx_t ctx) { slong length; length = CA_FIELD_LENGTH(K); if (length == 0) return; flint_free(CA_FIELD_EXT(K)); if (CA_FIELD_IS_NF(K)) return; fmpz_mpoly_vec_clear(CA_FIELD_IDEAL(K), CA_FIELD_MCTX(K, ctx)); } calcium-0.4.1/ca_field/cmp.c000066400000000000000000000112511407704557200156150ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" static int _fmpz_poly_compare_abslex(const fmpz * a, const fmpz * b, slong len) { slong i; int c; for (i = len - 1; i >= 0; i--) { if (!fmpz_equal(a + i, b + i)) { c = fmpz_cmpabs(a + i, b + i); if (c != 0) return c; return fmpz_sgn(a + i); } } return 0; } static int _nf_elem_cmp(const nf_elem_t x, const nf_elem_t y, const nf_t nf) { int c; if (nf->flag & NF_LINEAR) { return _fmpq_cmp(LNF_ELEM_NUMREF(x), LNF_ELEM_DENREF(x), LNF_ELEM_NUMREF(y), LNF_ELEM_DENREF(y)); } else if (nf->flag & NF_QUADRATIC) { c = _fmpz_poly_compare_abslex(QNF_ELEM_NUMREF(x), QNF_ELEM_NUMREF(y), 2); if (c != 0) return c; return fmpz_cmp(QNF_ELEM_DENREF(x), QNF_ELEM_DENREF(y)); } else { if (NF_ELEM(x)->length != NF_ELEM(y)->length) return (NF_ELEM(x)->length < NF_ELEM(y)->length) ? -1 : 1; c = _fmpz_poly_compare_abslex(NF_ELEM(x)->coeffs, NF_ELEM(y)->coeffs, NF_ELEM(x)->length); if (c != 0) return c; return fmpz_cmp(NF_ELEM_DENREF(x), NF_ELEM_DENREF(y)); } } /* todo: better algorithm extending fmpz_mpoly_cmp */ static int _fmpz_mpoly_cmp2(const fmpz_mpoly_t x, const fmpz_mpoly_t y, fmpz_mpoly_ctx_t ctx) { slong lenx, leny, nvars; mp_limb_t expx, expy; slong i, j; int c; lenx = x->length; leny = y->length; nvars = ctx->minfo->nvars; if (lenx != leny) return (lenx < leny) ? -1 : 1; for (i = 0; i < lenx; i++) { for (j = 0; j < nvars; j++) { expx = fmpz_mpoly_get_term_var_exp_ui(x, i, j, ctx); expy = fmpz_mpoly_get_term_var_exp_ui(y, i, j, ctx); if (expx != expy) return (expx < expy) ? -1 : 1; } } for (i = 0; i < lenx; i++) { c = fmpz_cmp(x->coeffs + i, y->coeffs + i); if (c != 0) return c; } return 0; } int _fmpz_mpoly_q_cmp(const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, fmpz_mpoly_ctx_t ctx) { int c; c = _fmpz_mpoly_cmp2(fmpz_mpoly_q_denref(x), fmpz_mpoly_q_denref(y), ctx); if (c != 0) return c; return _fmpz_mpoly_cmp2(fmpz_mpoly_q_numref(x), fmpz_mpoly_q_numref(y), ctx); } static __inline__ slong si_sign(slong x) { if (x != 0) x = (x > 0) ? 1 : -1; return x; } int ca_cmp_repr(const ca_t x, const ca_t y, ca_ctx_t ctx) { ca_field_srcptr xfield, yfield; if (CA_IS_SPECIAL(x) || CA_IS_SPECIAL(y)) { flint_printf("ca_cmp_repr: not implemented for special values\n"); flint_abort(); } xfield = CA_FIELD(x, ctx); yfield = CA_FIELD(y, ctx); if (xfield != yfield) return ca_field_cmp(xfield, yfield, ctx); if (CA_FIELD_IS_QQ(xfield)) { return si_sign(fmpq_cmp(CA_FMPQ(x), CA_FMPQ(y))); } else if (CA_FIELD_IS_NF(xfield)) { return si_sign(_nf_elem_cmp(CA_NF_ELEM(x), CA_NF_ELEM(y), CA_FIELD_NF(xfield))); } else { return si_sign(_fmpz_mpoly_q_cmp(CA_MPOLY_Q(x), CA_MPOLY_Q(y), CA_FIELD_MCTX(xfield, ctx))); } } slong ca_field_depth(const ca_field_t K, ca_ctx_t ctx); slong ca_depth(const ca_t x, ca_ctx_t ctx) { if (CA_IS_SPECIAL(x)) flint_abort(); return ca_field_depth(CA_FIELD(x, ctx), ctx); } static slong ca_ext_depth(const ca_ext_t x, ca_ctx_t ctx) { return CA_EXT_DEPTH(x); } slong ca_field_depth(const ca_field_t K, ca_ctx_t ctx) { if (CA_FIELD_LENGTH(K) >= 1) { slong i, depth, depth_i; depth = 0; for (i = 0; i < CA_FIELD_LENGTH(K); i++) { depth_i = ca_ext_depth(CA_FIELD_EXT_ELEM(K, i), ctx); depth = FLINT_MAX(depth, depth_i); } return depth + 1; } return 0; } /* todo: sort on depth? */ int ca_field_cmp(const ca_field_t K1, const ca_field_t K2, ca_ctx_t ctx) { slong i, len1, len2; len1 = CA_FIELD_LENGTH(K1); len2 = CA_FIELD_LENGTH(K2); if (len1 != len2) return (len1 < len2) ? -1 : 1; for (i = 0; i < len1; i++) { int c = ca_ext_cmp_repr(CA_FIELD_EXT_ELEM(K1, i), CA_FIELD_EXT_ELEM(K2, i), ctx); if (c != 0) return c; } return 0; } calcium-0.4.1/ca_field/init.c000066400000000000000000000074421407704557200160100ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" void _ca_ctx_init_mctx(ca_ctx_t ctx, slong len) { while (ctx->mctx_len < len) { slong i, alloc; alloc = FLINT_MAX(1, 2 * ctx->mctx_len); ctx->mctx = flint_realloc(ctx->mctx, alloc * sizeof(fmpz_mpoly_ctx_struct *)); for (i = ctx->mctx_len; i < alloc; i++) { ctx->mctx[i] = flint_malloc(sizeof(fmpz_mpoly_ctx_struct)); fmpz_mpoly_ctx_init(ctx->mctx[i], i + 1, ctx->options[CA_OPT_MPOLY_ORD]); } ctx->mctx_len = alloc; } } void ca_field_init_qq(ca_field_t K, ca_ctx_t ctx) { CA_FIELD_LENGTH(K) = 0; CA_FIELD_EXT(K) = NULL; CA_FIELD_IDEAL_P(K) = NULL; CA_FIELD_IDEAL_LENGTH(K) = 0; CA_FIELD_IDEAL_ALLOC(K) = 0; CA_FIELD_HASH(K) = 0; } void ca_field_init_nf(ca_field_t K, const qqbar_t x, ca_ctx_t ctx) { ca_ext_ptr ext; ca_ext_t tmp; /* todo: avoid unnecessary work (especially the nf_t init) */ ca_ext_init_qqbar(tmp, x, ctx); ext = ca_ext_cache_insert(CA_CTX_EXT_CACHE(ctx), tmp, ctx); ca_ext_clear(tmp, ctx); CA_FIELD_LENGTH(K) = 1; CA_FIELD_EXT(K) = flint_malloc(sizeof(ca_ext_ptr)); CA_FIELD_EXT_ELEM(K, 0) = ext; CA_FIELD_IDEAL_P(K) = NULL; CA_FIELD_IDEAL_LENGTH(K) = -1; CA_FIELD_IDEAL_ALLOC(K) = 0; CA_FIELD_HASH(K) = CA_EXT_HASH(ext); } void ca_field_init_const(ca_field_t K, calcium_func_code func, ca_ctx_t ctx) { ca_ext_ptr ext; ca_ext_t tmp; /* todo: avoid unnecessary work */ ca_ext_init_const(tmp, func, ctx); ext = ca_ext_cache_insert(CA_CTX_EXT_CACHE(ctx), tmp, ctx); ca_ext_clear(tmp, ctx); CA_FIELD_LENGTH(K) = 1; CA_FIELD_EXT(K) = flint_malloc(sizeof(ca_ext_ptr)); CA_FIELD_EXT_ELEM(K, 0) = ext; CA_FIELD_IDEAL_P(K) = NULL; CA_FIELD_IDEAL_LENGTH(K) = 0; CA_FIELD_IDEAL_ALLOC(K) = 0; CA_FIELD_HASH(K) = CA_EXT_HASH(ext); _ca_ctx_init_mctx(ctx, 1); } void ca_field_init_fx(ca_field_t K, calcium_func_code func, const ca_t x, ca_ctx_t ctx) { ca_ext_ptr ext; ca_ext_t tmp; /* todo: avoid unnecessary work */ ca_ext_init_fx(tmp, func, x, ctx); ext = ca_ext_cache_insert(CA_CTX_EXT_CACHE(ctx), tmp, ctx); ca_ext_clear(tmp, ctx); CA_FIELD_LENGTH(K) = 1; CA_FIELD_EXT(K) = flint_malloc(sizeof(ca_ext_ptr)); CA_FIELD_EXT_ELEM(K, 0) = ext; CA_FIELD_IDEAL_P(K) = NULL; CA_FIELD_IDEAL_LENGTH(K) = 0; CA_FIELD_IDEAL_ALLOC(K) = 0; CA_FIELD_HASH(K) = CA_EXT_HASH(ext); _ca_ctx_init_mctx(ctx, 1); } void ca_field_init_fxy(ca_field_t K, calcium_func_code func, const ca_t x, const ca_t y, ca_ctx_t ctx) { ca_ext_ptr ext; ca_ext_t tmp; /* todo: avoid unnecessary work */ ca_ext_init_fxy(tmp, func, x, y, ctx); ext = ca_ext_cache_insert(CA_CTX_EXT_CACHE(ctx), tmp, ctx); ca_ext_clear(tmp, ctx); CA_FIELD_LENGTH(K) = 1; CA_FIELD_EXT(K) = flint_malloc(sizeof(ca_ext_ptr)); CA_FIELD_EXT_ELEM(K, 0) = ext; CA_FIELD_IDEAL_P(K) = NULL; CA_FIELD_IDEAL_LENGTH(K) = 0; CA_FIELD_IDEAL_ALLOC(K) = 0; CA_FIELD_HASH(K) = CA_EXT_HASH(ext); _ca_ctx_init_mctx(ctx, 2); } void ca_field_init_multi(ca_field_t K, slong len, ca_ctx_t ctx) { CA_FIELD_LENGTH(K) = len; CA_FIELD_EXT(K) = flint_malloc(len * sizeof(ca_ext_ptr)); CA_FIELD_IDEAL_P(K) = NULL; CA_FIELD_IDEAL_LENGTH(K) = 0; CA_FIELD_IDEAL_ALLOC(K) = 0; CA_FIELD_HASH(K) = 0; _ca_ctx_init_mctx(ctx, len); } calcium-0.4.1/ca_field/inlines.c000066400000000000000000000006661407704557200165070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #define CA_FIELD_INLINES_C #include "ca_field.h" calcium-0.4.1/ca_field/print.c000066400000000000000000000026251407704557200161770ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" void ca_field_print(const ca_field_t K, ca_ctx_t ctx) { slong i, len, ideal_len; flint_printf("QQ"); len = CA_FIELD_LENGTH(K); if (len == 0) return; flint_printf("("); for (i = 0; i < len; i++) { flint_printf("x%wd", i + 1); if (i < len - 1) flint_printf(", "); } flint_printf(") where {"); for (i = 0; i < len; i++) { flint_printf("x%wd = ", i + 1); ca_ext_print(CA_FIELD_EXT_ELEM(K, i), ctx); flint_printf(""); if (i < len - 1) flint_printf(", "); } flint_printf("}"); ideal_len = CA_FIELD_IDEAL_LENGTH(K); if (ideal_len > 0) { flint_printf(" with ideal {"); for (i = 0; i < ideal_len; i++) { fmpz_mpoly_print_pretty(CA_FIELD_IDEAL_ELEM(K, i), NULL, CA_FIELD_MCTX(K, ctx)); if (i < ideal_len - 1) flint_printf(", "); } flint_printf("}"); } } calcium-0.4.1/ca_field/set_ext.c000066400000000000000000000012011407704557200165030ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" void ca_field_set_ext(ca_field_t K, slong i, ca_ext_srcptr x, ca_ctx_t ctx) { CA_FIELD_EXT_ELEM(K, i) = (ca_ext_ptr) x; CA_FIELD_HASH(K) = CA_FIELD_HASH(K) * 100003 + CA_EXT_HASH(x); } calcium-0.4.1/ca_field/test/000077500000000000000000000000001407704557200156515ustar00rootroot00000000000000calcium-0.4.1/ca_field/test/t-cache_insert.c000066400000000000000000000057221407704557200207130ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca.h" #include "ca_ext.h" #include "ca_field.h" static int _ca_field_equal_ext(const ca_field_t K, ca_ext_struct ** x, slong len, ca_ctx_t ctx) { slong i; if (len != CA_FIELD_LENGTH(K)) return 0; for (i = 0; i < len; i++) if (CA_FIELD_EXT_ELEM(K, i) != x[i]) return 0; return 1; } int main() { slong iter; flint_rand_t state; flint_printf("cache_insert...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_ext_struct ** ext; ca_ext_struct * all_ext; ca_field_cache_t cache; ca_field_struct *K, *K2; qqbar_t x; ca_t v; slong i, j, steps, len, ext_len; ca_ctx_init(ctx); qqbar_init(x); ca_init(v, ctx); ext_len = 1 + n_randint(state, 10); steps = n_randint(state, 100); all_ext = flint_malloc(sizeof(ca_ext_struct) * ext_len); for (j = 0; j < ext_len; j++) { if (n_randint(state, 10) != 0) { ca_set_ui(v, j + 2, ctx); ca_ext_init_fx(all_ext + j, CA_RiemannZeta, v, ctx); } else { qqbar_set_ui(x, j); ca_ext_init_qqbar(all_ext + j, x, ctx); } } ca_field_cache_init(cache, ctx); for (i = 0; i < steps; i++) { len = n_randint(state, 10); ext = flint_malloc(len * sizeof(ca_ext_struct *)); for (j = 0; j < len; j++) ext[j] = all_ext + n_randint(state, ext_len); K = ca_field_cache_insert_ext(cache, ext, len, ctx); K2 = ca_field_cache_insert_ext(cache, ext, len, ctx); if (!_ca_field_equal_ext(K, ext, len, ctx) || K != K2) { flint_printf("FAIL\n\n"); flint_printf("K = "); ca_field_print(K, ctx); flint_printf("\n\n"); flint_printf("ext = \n\n"); for (j = 0; j < len; j++) { ca_ext_print(ext[j], ctx); flint_printf("\n\n"); } flint_abort(); } flint_free(ext); } for (j = 0; j < ext_len; j++) ca_ext_clear(all_ext + j, ctx); flint_free(all_ext); ca_field_cache_clear(cache, ctx); ca_clear(v, ctx); ca_ctx_clear(ctx); qqbar_clear(x); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat.h000066400000000000000000000302251407704557200145430ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef CA_MAT_H #define CA_MAT_H #ifdef CA_MAT_INLINES_C #define CA_MAT_INLINE #else #define CA_MAT_INLINE static __inline__ #endif #include #include "flint/flint.h" #include "flint/fmpz_mat.h" #include "flint/fmpq_mat.h" #include "flint/perm.h" #include "arb_mat.h" #include "acb_mat.h" #include "antic/nf.h" #include "antic/nf_elem.h" #include "ca.h" #include "ca_vec.h" #include "ca_poly.h" #ifdef __cplusplus extern "C" { #endif /* Matrix object */ typedef struct { ca_ptr entries; slong r; slong c; ca_ptr * rows; } ca_mat_struct; typedef ca_mat_struct ca_mat_t[1]; #define ca_mat_entry(mat,i,j) ((mat)->rows[i] + (j)) #define ca_mat_nrows(mat) ((mat)->r) #define ca_mat_ncols(mat) ((mat)->c) CA_MAT_INLINE ca_ptr ca_mat_entry_ptr(ca_mat_t mat, slong i, slong j) { return ca_mat_entry(mat, i, j); } /* Memory management */ void ca_mat_init(ca_mat_t mat, slong r, slong c, ca_ctx_t ctx); void ca_mat_clear(ca_mat_t mat, ca_ctx_t ctx); CA_MAT_INLINE void ca_mat_swap(ca_mat_t mat1, ca_mat_t mat2, ca_ctx_t ctx) { ca_mat_struct t = *mat1; *mat1 = *mat2; *mat2 = t; } /* Window matrices */ void ca_mat_window_init(ca_mat_t window, const ca_mat_t mat, slong r1, slong c1, slong r2, slong c2, ca_ctx_t ctx); CA_MAT_INLINE void ca_mat_window_clear(ca_mat_t window, ca_ctx_t ctx) { flint_free(window->rows); } /* Shape */ CA_MAT_INLINE int ca_mat_is_empty(const ca_mat_t mat) { return (mat->r == 0) || (mat->c == 0); } CA_MAT_INLINE int ca_mat_is_square(const ca_mat_t mat) { return (mat->r == mat->c); } /* Conversions */ void ca_mat_set(ca_mat_t dest, const ca_mat_t src, ca_ctx_t ctx); void ca_mat_set_fmpz_mat(ca_mat_t dest, const fmpz_mat_t src, ca_ctx_t ctx); void ca_mat_set_fmpq_mat(ca_mat_t dest, const fmpq_mat_t src, ca_ctx_t ctx); void ca_mat_set_ca(ca_mat_t y, const ca_t x, ca_ctx_t ctx); void ca_mat_transfer(ca_mat_t res, ca_ctx_t res_ctx, const ca_mat_t src, ca_ctx_t src_ctx); /* Random generation */ void ca_mat_randtest(ca_mat_t mat, flint_rand_t state, slong len, slong bits, ca_ctx_t ctx); void ca_mat_randtest_rational(ca_mat_t mat, flint_rand_t state, slong bits, ca_ctx_t ctx); void ca_mat_randops(ca_mat_t mat, flint_rand_t state, slong count, ca_ctx_t ctx); /* I/O */ void ca_mat_print(const ca_mat_t mat, ca_ctx_t ctx); void ca_mat_printn(const ca_mat_t mat, slong digits, ca_ctx_t ctx); /* Special matrices */ void ca_mat_zero(ca_mat_t mat, ca_ctx_t ctx); void ca_mat_one(ca_mat_t mat, ca_ctx_t ctx); void ca_mat_ones(ca_mat_t mat, ca_ctx_t ctx); void ca_mat_pascal(ca_mat_t mat, int triangular, ca_ctx_t ctx); void ca_mat_stirling(ca_mat_t mat, int kind, ca_ctx_t ctx); void ca_mat_hilbert(ca_mat_t mat, ca_ctx_t ctx); void ca_mat_dft(ca_mat_t res, int type, ca_ctx_t ctx); /* Comparisons and properties */ truth_t ca_mat_check_equal(const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx); truth_t ca_mat_check_is_zero(const ca_mat_t A, ca_ctx_t ctx); truth_t ca_mat_check_is_one(const ca_mat_t A, ca_ctx_t ctx); /* Conjugate and transpose */ void ca_mat_transpose(ca_mat_t B, const ca_mat_t A, ca_ctx_t ctx); void ca_mat_conj(ca_mat_t B, const ca_mat_t A, ca_ctx_t ctx); void ca_mat_conj_transpose(ca_mat_t mat1, const ca_mat_t mat2, ca_ctx_t ctx); /* Arithmetic */ void ca_mat_add_ca(ca_mat_t y, const ca_mat_t a, const ca_t x, ca_ctx_t ctx); void ca_mat_sub_ca(ca_mat_t y, const ca_mat_t a, const ca_t x, ca_ctx_t ctx); void ca_mat_addmul_ca(ca_mat_t y, const ca_mat_t a, const ca_t x, ca_ctx_t ctx); void ca_mat_submul_ca(ca_mat_t y, const ca_mat_t a, const ca_t x, ca_ctx_t ctx); void ca_mat_neg(ca_mat_t dest, const ca_mat_t src, ca_ctx_t ctx); void ca_mat_add(ca_mat_t res, const ca_mat_t mat1, const ca_mat_t mat2, ca_ctx_t ctx); void ca_mat_sub(ca_mat_t res, const ca_mat_t mat1, const ca_mat_t mat2, ca_ctx_t ctx); void ca_mat_mul(ca_mat_t C, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx); void ca_mat_mul_classical(ca_mat_t C, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx); void ca_mat_mul_same_nf(ca_mat_t C, const ca_mat_t A, const ca_mat_t B, ca_field_t K, ca_ctx_t ctx); CA_MAT_INLINE void ca_mat_mul_si(ca_mat_t B, const ca_mat_t A, slong c, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(A); i++) for (j = 0; j < ca_mat_ncols(A); j++) ca_mul_si(ca_mat_entry(B, i, j), ca_mat_entry(A, i, j), c, ctx); } CA_MAT_INLINE void ca_mat_mul_fmpz(ca_mat_t B, const ca_mat_t A, const fmpz_t c, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(A); i++) for (j = 0; j < ca_mat_ncols(A); j++) ca_mul_fmpz(ca_mat_entry(B, i, j), ca_mat_entry(A, i, j), c, ctx); } CA_MAT_INLINE void ca_mat_mul_fmpq(ca_mat_t B, const ca_mat_t A, const fmpq_t c, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(A); i++) for (j = 0; j < ca_mat_ncols(A); j++) ca_mul_fmpq(ca_mat_entry(B, i, j), ca_mat_entry(A, i, j), c, ctx); } CA_MAT_INLINE void ca_mat_mul_ca(ca_mat_t B, const ca_mat_t A, const ca_t c, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(A); i++) for (j = 0; j < ca_mat_ncols(A); j++) ca_mul(ca_mat_entry(B, i, j), ca_mat_entry(A, i, j), c, ctx); } CA_MAT_INLINE void ca_mat_div_si(ca_mat_t B, const ca_mat_t A, slong c, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(A); i++) for (j = 0; j < ca_mat_ncols(A); j++) ca_div_si(ca_mat_entry(B, i, j), ca_mat_entry(A, i, j), c, ctx); } CA_MAT_INLINE void ca_mat_div_fmpz(ca_mat_t B, const ca_mat_t A, const fmpz_t c, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(A); i++) for (j = 0; j < ca_mat_ncols(A); j++) ca_div_fmpz(ca_mat_entry(B, i, j), ca_mat_entry(A, i, j), c, ctx); } CA_MAT_INLINE void ca_mat_div_fmpq(ca_mat_t B, const ca_mat_t A, const fmpq_t c, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(A); i++) for (j = 0; j < ca_mat_ncols(A); j++) ca_div_fmpq(ca_mat_entry(B, i, j), ca_mat_entry(A, i, j), c, ctx); } CA_MAT_INLINE void ca_mat_div_ca(ca_mat_t B, const ca_mat_t A, const ca_t c, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(A); i++) for (j = 0; j < ca_mat_ncols(A); j++) ca_div(ca_mat_entry(B, i, j), ca_mat_entry(A, i, j), c, ctx); } CA_MAT_INLINE void ca_mat_sqr(ca_mat_t res, const ca_mat_t A, ca_ctx_t ctx) { ca_mat_mul(res, A, A, ctx); } void ca_mat_pow_ui_binexp(ca_mat_t B, const ca_mat_t A, ulong exp, ca_ctx_t ctx); /* Polynomial evaluation */ void _ca_mat_ca_poly_evaluate(ca_mat_t y, ca_srcptr poly, slong len, const ca_mat_t x, ca_ctx_t ctx); void ca_mat_ca_poly_evaluate(ca_mat_t res, const ca_poly_t f, const ca_mat_t a, ca_ctx_t ctx); /* Trace */ void ca_mat_trace(ca_t trace, const ca_mat_t mat, ca_ctx_t ctx); /* Gaussian elimination, solving and inverse */ truth_t ca_mat_find_pivot(slong * pivot_row, ca_mat_t mat, slong start_row, slong end_row, slong column, ca_ctx_t ctx); CA_MAT_INLINE void _ca_mat_swap_rows(ca_mat_t mat, slong * perm, slong r, slong s) { if (r != s) { ca_ptr u; slong t; if (perm != NULL) { t = perm[s]; perm[s] = perm[r]; perm[r] = t; } u = mat->rows[s]; mat->rows[s] = mat->rows[r]; mat->rows[r] = u; } } int ca_mat_lu_classical(slong * rank, slong * P, ca_mat_t LU, const ca_mat_t A, int rank_check, ca_ctx_t ctx); int ca_mat_lu_recursive(slong * rank, slong * P, ca_mat_t LU, const ca_mat_t A, int rank_check, ca_ctx_t ctx); int ca_mat_lu(slong * rank, slong * P, ca_mat_t LU, const ca_mat_t A, int rank_check, ca_ctx_t ctx); int ca_mat_fflu(slong * rank, slong * P, ca_mat_t LU, ca_t den, const ca_mat_t A, int rank_check, ca_ctx_t ctx); int ca_mat_rref_fflu(slong * rank, ca_mat_t R, const ca_mat_t A, ca_ctx_t ctx); int ca_mat_rref_lu(slong * rank, ca_mat_t R, const ca_mat_t A, ca_ctx_t ctx); int ca_mat_rref(slong * rank, ca_mat_t R, const ca_mat_t A, ca_ctx_t ctx); truth_t ca_mat_nonsingular_lu(slong * P, ca_mat_t LU, const ca_mat_t A, ca_ctx_t ctx); truth_t ca_mat_nonsingular_fflu(slong * P, ca_mat_t LU, ca_t den, const ca_mat_t A, ca_ctx_t ctx); truth_t ca_mat_nonsingular_solve_adjugate(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx); truth_t ca_mat_nonsingular_solve_fflu(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx); truth_t ca_mat_nonsingular_solve_lu(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx); truth_t ca_mat_nonsingular_solve(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx); truth_t ca_mat_inv(ca_mat_t X, const ca_mat_t A, ca_ctx_t ctx); void ca_mat_solve_tril_classical(ca_mat_t X, const ca_mat_t L, const ca_mat_t B, int unit, ca_ctx_t ctx); void ca_mat_solve_tril_recursive(ca_mat_t X, const ca_mat_t L, const ca_mat_t B, int unit, ca_ctx_t ctx); void ca_mat_solve_tril(ca_mat_t X, const ca_mat_t L, const ca_mat_t B, int unit, ca_ctx_t ctx); void ca_mat_solve_triu_classical(ca_mat_t X, const ca_mat_t U, const ca_mat_t B, int unit, ca_ctx_t ctx); void ca_mat_solve_triu_recursive(ca_mat_t X, const ca_mat_t U, const ca_mat_t B, int unit, ca_ctx_t ctx); void ca_mat_solve_triu(ca_mat_t X, const ca_mat_t U, const ca_mat_t B, int unit, ca_ctx_t ctx); void ca_mat_solve_lu_precomp(ca_mat_t X, const slong * perm, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx); void ca_mat_solve_fflu_precomp(ca_mat_t X, const slong * perm, const ca_mat_t A, const ca_t den, const ca_mat_t B, ca_ctx_t ctx); /* Rank and kernel */ int ca_mat_rank(slong * rank, const ca_mat_t A, ca_ctx_t ctx); int ca_mat_right_kernel(ca_mat_t X, const ca_mat_t A, ca_ctx_t ctx); /* Determinant */ void ca_mat_det_berkowitz(ca_t det, const ca_mat_t A, ca_ctx_t ctx); int ca_mat_det_lu(ca_t det, const ca_mat_t A, ca_ctx_t ctx); int ca_mat_det_bareiss(ca_t det, const ca_mat_t A, ca_ctx_t ctx); void ca_mat_det_cofactor(ca_t det, const ca_mat_t A, ca_ctx_t ctx); void ca_mat_det(ca_t det, const ca_mat_t A, ca_ctx_t ctx); void ca_mat_adjugate_cofactor(ca_mat_t adj, ca_t det, const ca_mat_t A, ca_ctx_t ctx); void ca_mat_adjugate_charpoly(ca_mat_t adj, ca_t det, const ca_mat_t A, ca_ctx_t ctx); void ca_mat_adjugate(ca_mat_t adj, ca_t det, const ca_mat_t A, ca_ctx_t ctx); /* Characteristic polynomial */ void _ca_mat_charpoly_berkowitz(ca_ptr cp, const ca_mat_t mat, ca_ctx_t ctx); void ca_mat_charpoly_berkowitz(ca_poly_t cp, const ca_mat_t mat, ca_ctx_t ctx); int _ca_mat_charpoly_danilevsky(ca_ptr p, const ca_mat_t A, ca_ctx_t ctx); int ca_mat_charpoly_danilevsky(ca_poly_t cp, const ca_mat_t mat, ca_ctx_t ctx); void _ca_mat_charpoly(ca_ptr cp, const ca_mat_t mat, ca_ctx_t ctx); void ca_mat_charpoly(ca_poly_t cp, const ca_mat_t mat, ca_ctx_t ctx); int ca_mat_companion(ca_mat_t A, const ca_poly_t poly, ca_ctx_t ctx); /* Eigenvalues and eigenvectors */ int ca_mat_eigenvalues(ca_vec_t lambda, ulong * exp, const ca_mat_t mat, ca_ctx_t ctx); /* Diagonalization */ truth_t ca_mat_diagonalization(ca_mat_t D, ca_mat_t P, const ca_mat_t A, ca_ctx_t ctx); void ca_mat_set_jordan_blocks(ca_mat_t mat, const ca_vec_t lambda, slong num_blocks, slong * block_lambda, slong * block_size, ca_ctx_t ctx); int ca_mat_jordan_blocks(ca_vec_t lambda, slong * num_blocks, slong * block_lambda, slong * block_size, const ca_mat_t A, ca_ctx_t ctx); int ca_mat_jordan_transformation(ca_mat_t mat, const ca_vec_t lambda, slong num_blocks, slong * block_lambda, slong * block_size, const ca_mat_t A, ca_ctx_t ctx); int ca_mat_jordan_form(ca_mat_t J, ca_mat_t P, const ca_mat_t A, ca_ctx_t ctx); /* Matrix functions */ int ca_mat_exp(ca_mat_t res, const ca_mat_t A, ca_ctx_t ctx); truth_t ca_mat_log(ca_mat_t res, const ca_mat_t A, ca_ctx_t ctx); /* Internal representation */ /* todo: document, make consistent */ ca_field_ptr _ca_mat_same_field(const ca_mat_t A, ca_ctx_t ctx); ca_field_ptr _ca_mat_same_field2(const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx); #ifdef __cplusplus } #endif #endif calcium-0.4.1/ca_mat/000077500000000000000000000000001407704557200143705ustar00rootroot00000000000000calcium-0.4.1/ca_mat/add.c000066400000000000000000000013601407704557200152640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_add(ca_mat_t res, const ca_mat_t mat1, const ca_mat_t mat2, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(mat1); i++) for (j = 0; j < ca_mat_ncols(mat1); j++) ca_add(ca_mat_entry(res, i, j), ca_mat_entry(mat1, i, j), ca_mat_entry(mat2, i, j), ctx); } calcium-0.4.1/ca_mat/add_ca.c000066400000000000000000000020641407704557200157310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_add_ca(ca_mat_t y, const ca_mat_t a, const ca_t x, ca_ctx_t ctx) { slong i, j, n; if (a == y) { n = FLINT_MIN(ca_mat_nrows(a), ca_mat_ncols(a)); for (i = 0; i < n; i++) ca_add(ca_mat_entry(y, i, i), ca_mat_entry(y, i, i), x, ctx); } else { for (i = 0; i < ca_mat_nrows(a); i++) { for (j = 0; j < ca_mat_ncols(a); j++) { if (i == j) ca_add(ca_mat_entry(y, i, j), ca_mat_entry(a, i, j), x, ctx); else ca_set(ca_mat_entry(y, i, j), ca_mat_entry(a, i, j), ctx); } } } } calcium-0.4.1/ca_mat/addmul_ca.c000066400000000000000000000014571407704557200164540ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_addmul_ca(ca_mat_t y, const ca_mat_t a, const ca_t x, ca_ctx_t ctx) { slong i, j; ca_t t; ca_init(t, ctx); for (i = 0; i < ca_mat_nrows(a); i++) { for (j = 0; j < ca_mat_ncols(a); j++) { ca_mul(t, ca_mat_entry(a, i, j), x, ctx); ca_add(ca_mat_entry(y, i, j), ca_mat_entry(y, i, j), t, ctx); } } ca_clear(t, ctx); } calcium-0.4.1/ca_mat/adjugate.c000066400000000000000000000011711407704557200163200ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_adjugate(ca_mat_t adj, ca_t det, const ca_mat_t A, ca_ctx_t ctx) { if (ca_mat_nrows(A) <= 5) ca_mat_adjugate_cofactor(adj, det, A, ctx); else ca_mat_adjugate_charpoly(adj, det, A, ctx); } calcium-0.4.1/ca_mat/adjugate_charpoly.c000066400000000000000000000016701407704557200202250ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_adjugate_charpoly(ca_mat_t adj, ca_t det, const ca_mat_t A, ca_ctx_t ctx) { ca_poly_t pol; slong n; n = ca_mat_nrows(A); if (n == 0) { ca_one(det, ctx); return; } ca_poly_init(pol, ctx); ca_mat_charpoly(pol, A, ctx); ca_swap(det, ca_poly_coeff_ptr(pol, 0), ctx); ca_poly_shift_right(pol, pol, 1, ctx); ca_mat_ca_poly_evaluate(adj, pol, A, ctx); if (n % 2) ca_neg(det, det, ctx); else ca_mat_neg(adj, adj, ctx); ca_poly_clear(pol, ctx); } calcium-0.4.1/ca_mat/adjugate_cofactor.c000066400000000000000000000051521407704557200202030ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_adjugate_cofactor(ca_mat_t adj, ca_t det, const ca_mat_t A, ca_ctx_t ctx) { ca_mat_t T; slong i, j, n, a, b; ca_t t, zero; n = ca_mat_nrows(A); if (n == 0) { ca_one(det, ctx); return; } if (n == 1) { ca_set(det, ca_mat_entry(A, 0, 0), ctx); ca_one(ca_mat_entry(adj, 0, 0), ctx); return; } if (n == 2) { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); ca_mul(t, ca_mat_entry(A, 0, 0), ca_mat_entry(A, 1, 1), ctx); ca_mul(u, ca_mat_entry(A, 0, 1), ca_mat_entry(A, 1, 0), ctx); ca_set(ca_mat_entry(adj, 0, 0), ca_mat_entry(A, 1, 1), ctx); ca_neg(ca_mat_entry(adj, 0, 1), ca_mat_entry(A, 0, 1), ctx); ca_neg(ca_mat_entry(adj, 1, 0), ca_mat_entry(A, 1, 0), ctx); ca_set(ca_mat_entry(adj, 1, 1), ca_mat_entry(A, 0, 0), ctx); ca_sub(det, t, u, ctx); ca_clear(t, ctx); ca_clear(u, ctx); return; } if (adj == A) { ca_mat_init(T, n, n, ctx); ca_mat_adjugate_cofactor(T, det, A, ctx); ca_mat_swap(adj, T, ctx); ca_mat_clear(T, ctx); return; } ca_mat_init(T, n - 1, n - 1, ctx); ca_init(zero, ctx); ca_init(t, ctx); ca_zero(det, ctx); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { for (a = 0; a < n; a++) { for (b = 0; b < n; b++) { if (a != i && b != j) { *ca_mat_entry(T, a - (a > i), b - (b > j)) = *ca_mat_entry(A, a, b); } } } ca_mat_det(ca_mat_entry(adj, i, j), T, ctx); if ((i + j) & 1) ca_neg(ca_mat_entry(adj, i, j), ca_mat_entry(adj, i, j), ctx); if (i == 0) { ca_mul(t, ca_mat_entry(adj, i, j), ca_mat_entry(A, i, j), ctx); ca_add(det, det, t, ctx); } } } ca_mat_transpose(adj, adj, ctx); for (i = 0; i < n - 1; i++) for (j = 0; j < n - 1; j++) *ca_mat_entry(T, i, j) = *zero; ca_mat_clear(T, ctx); ca_clear(t, ctx); } calcium-0.4.1/ca_mat/ca_poly_evaluate.c000066400000000000000000000040311407704557200200460ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void _ca_mat_ca_poly_evaluate(ca_mat_t y, ca_srcptr poly, slong len, const ca_mat_t x, ca_ctx_t ctx) { slong i, j, m, r, n; ca_mat_struct * xs; ca_mat_t s, t; if (len == 0) { ca_mat_zero(y, ctx); return; } if (len == 1) { ca_mat_set_ca(y, poly + 0, ctx); return; } if (len == 2) { ca_mat_mul_ca(y, x, poly + 1, ctx); ca_mat_add_ca(y, y, poly + 0, ctx); return; } n = ca_mat_nrows(x); m = n_sqrt(len) + 1; r = (len + m - 1) / m; xs = flint_malloc(sizeof(ca_mat_struct) * (m + 1)); for (i = 0; i <= m; i++) { ca_mat_init(xs + i, n, n, ctx); if (i == 0) ca_mat_one(xs + i, ctx); else if (i == 1) ca_mat_set(xs + i, x, ctx); else ca_mat_mul(xs + i, xs + i - 1, x, ctx); } ca_mat_init(s, n, n, ctx); ca_mat_init(t, n, n, ctx); ca_mat_set_ca(y, poly + (r - 1) * m, ctx); for (j = 1; (r - 1) * m + j < len; j++) ca_mat_addmul_ca(y, xs + j, poly + (r - 1) * m + j, ctx); for (i = r - 2; i >= 0; i--) { ca_mat_set_ca(s, poly + i * m, ctx); for (j = 1; j < m; j++) ca_mat_addmul_ca(s, xs + j, poly + i * m + j, ctx); ca_mat_mul(y, y, xs + m, ctx); ca_mat_add(y, y, s, ctx); } for (i = 0; i <= m; i++) ca_mat_clear(xs + i, ctx); flint_free(xs); ca_mat_clear(s, ctx); ca_mat_clear(t, ctx); } void ca_mat_ca_poly_evaluate(ca_mat_t res, const ca_poly_t f, const ca_mat_t a, ca_ctx_t ctx) { _ca_mat_ca_poly_evaluate(res, f->coeffs, f->length, a, ctx); } calcium-0.4.1/ca_mat/charpoly.c000066400000000000000000000023031407704557200163530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void _ca_mat_charpoly(ca_ptr cp, const ca_mat_t mat, ca_ctx_t ctx) { if (ca_mat_nrows(mat) <= 2) { _ca_mat_charpoly_berkowitz(cp, mat, ctx); } else { /* ca_field_ptr K; K = _ca_mat_same_field(mat, ctx); if (0 && K != NULL && CA_FIELD_IS_NF(K)) { if (_ca_mat_charpoly_danilevsky(cp, mat, ctx)) return; } */ _ca_mat_charpoly_berkowitz(cp, mat, ctx); } } void ca_mat_charpoly(ca_poly_t cp, const ca_mat_t mat, ca_ctx_t ctx) { if (mat->r != mat->c) { flint_printf("Exception (ca_mat_charpoly). Non-square matrix.\n"); flint_abort(); } ca_poly_fit_length(cp, mat->r + 1, ctx); _ca_poly_set_length(cp, mat->r + 1, ctx); _ca_mat_charpoly(cp->coeffs, mat, ctx); } calcium-0.4.1/ca_mat/charpoly_berkowitz.c000066400000000000000000000046341407704557200204640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void _ca_mat_charpoly_berkowitz(ca_ptr cp, const ca_mat_t mat, ca_ctx_t ctx) { const slong n = mat->r; if (n == 0) { ca_one(cp, ctx); } else if (n == 1) { ca_neg(cp + 0, ca_mat_entry(mat, 0, 0), ctx); ca_one(cp + 1, ctx); } else if (n == 2) { ca_mat_det_cofactor(cp, mat, ctx); ca_add(cp + 1, ca_mat_entry(mat, 0, 0), ca_mat_entry(mat, 1, 1), ctx); ca_neg(cp + 1, cp + 1, ctx); ca_one(cp + 2, ctx); } else { slong i, k, t; ca_ptr a, A, s; a = _ca_vec_init(n * n, ctx); A = a + (n - 1) * n; _ca_vec_zero(cp, n + 1, ctx); ca_neg(cp + 0, ca_mat_entry(mat, 0, 0), ctx); for (t = 1; t < n; t++) { for (i = 0; i <= t; i++) { ca_set(a + 0 * n + i, ca_mat_entry(mat, i, t), ctx); } ca_set(A + 0, ca_mat_entry(mat, t, t), ctx); for (k = 1; k < t; k++) { for (i = 0; i <= t; i++) { s = a + k * n + i; ca_dot(s, NULL, 0, mat->rows[i], 1, a + (k - 1) * n, 1, t + 1, ctx); } ca_set(A + k, a + k * n + t, ctx); } ca_dot(A + t, NULL, 0, mat->rows[t], 1, a + (t - 1) * n, 1, t + 1, ctx); for (k = 0; k <= t; k++) { ca_dot(cp + k, cp + k, 1, A, 1, cp + k - 1, -1, k, ctx); ca_sub(cp + k, cp + k, A + k, ctx); } } /* Shift all coefficients up by one */ for (i = n; i > 0; i--) ca_swap(cp + i, cp + (i - 1), ctx); ca_one(cp + 0, ctx); _ca_poly_reverse(cp, cp, n + 1, n + 1, ctx); _ca_vec_clear(a, n * n, ctx); } } void ca_mat_charpoly_berkowitz(ca_poly_t cp, const ca_mat_t mat, ca_ctx_t ctx) { ca_poly_fit_length(cp, mat->r + 1, ctx); _ca_poly_set_length(cp, mat->r + 1, ctx); _ca_mat_charpoly_berkowitz(cp->coeffs, mat, ctx); } calcium-0.4.1/ca_mat/charpoly_danilevsky.c000066400000000000000000000151131407704557200206070ustar00rootroot00000000000000/* Copyright (C) 2015 William Hart Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" /* todo: use dot products */ int _ca_mat_charpoly_danilevsky_inplace(ca_ptr p, ca_mat_t A, ca_ctx_t ctx) { slong n, n_input; slong i, j, k; ca_ptr V, W, T; ca_ptr t, b; ca_t c, h; int success; truth_t is_zero; slong plen; n = n_input = ca_mat_nrows(A); if (n == 0) { ca_one(p, ctx); return 1; } if (n == 1) { ca_neg(p + 0, ca_mat_entry(A, 0, 0), ctx); ca_one(p + 1, ctx); return 1; } ca_init(c, ctx); success = 1; i = 1; ca_init(h, ctx); ca_one(p, ctx); plen = 1; t = _ca_vec_init(n + 1, ctx); b = _ca_vec_init(n + 1, ctx); V = _ca_vec_init(n, ctx); W = _ca_vec_init(n, ctx); T = _ca_vec_init(n, ctx); while (i < n) { ca_set(h, ca_mat_entry(A, n - i, n - i - 1), ctx); while (1) { is_zero = ca_check_is_zero(h, ctx); if (is_zero == T_FALSE) break; if (is_zero == T_UNKNOWN) { success = 0; goto cleanup; } k = 1; while (k < n - i) { is_zero = ca_check_is_zero(ca_mat_entry(A, n - i, n - i - k - 1), ctx); if (is_zero == T_FALSE) break; if (is_zero == T_UNKNOWN) { success = 0; goto cleanup; } k++; } if (k == n - i) { ca_one(b + i, ctx); for (k = 1; k <= i; k++) ca_neg(b + k - 1, ca_mat_entry(A, n - i, n - k), ctx); _ca_poly_mul(t, p, plen, b, i + 1, ctx); plen += i; _ca_vec_swap(p, t, plen, ctx); n -= i; i = 1; if (n == 1) { ca_one(b + 1, ctx); ca_neg(b, ca_mat_entry(A, 0, 0), ctx); _ca_poly_mul(t, p, plen, b, 2, ctx); plen += 1; _ca_vec_swap(p, t, plen, ctx); goto cleanup; } } else { ca_ptr ptr; ptr = A->rows[n - i - k - 1]; A->rows[n - i - k - 1] = A->rows[n - i - 1]; A->rows[n - i - 1] = ptr; for (j = 1; j <= n - i + 1; j++) { ca_swap(ca_mat_entry(A, j - 1, n - i - k - 1), ca_mat_entry(A, j - 1, n - i - 1), ctx); } } ca_set(h, ca_mat_entry(A, n - i, n - i - 1), ctx); } ca_neg(h, h, ctx); ca_inv(h, h, ctx); for (j = 1; j <= n; j++) { ca_mul(V + j - 1, ca_mat_entry(A, n - i, j - 1), h, ctx); ca_set(W + j - 1, ca_mat_entry(A, n - i, j - 1), ctx); } ca_neg(h, h, ctx); for (j = 1; j <= n - i; j++) { for (k = 1; k <= n - i - 1; k++) { ca_mul(c, ca_mat_entry(A, j - 1, n - i - 1), V + k - 1, ctx); ca_add(ca_mat_entry(A, j - 1, k - 1), ca_mat_entry(A, j - 1, k - 1), c, ctx); } for (k = n - i + 1; k <= n; k++) { ca_mul(c, ca_mat_entry(A, j - 1, n - i - 1), V + k - 1, ctx); ca_add(ca_mat_entry(A, j - 1, k - 1), ca_mat_entry(A, j - 1, k - 1), c, ctx); } ca_mul(ca_mat_entry(A, j - 1, n - i - 1), ca_mat_entry(A, j - 1, n - i - 1), h, ctx); } for (j = 1; j <= n - i - 1; j++) { ca_mul(ca_mat_entry(A, n - i - 1, j - 1), ca_mat_entry(A, n - i - 1, j - 1), W + n - i - 1, ctx); for (k = 1; k < n - i; k++) { ca_mul(c, ca_mat_entry(A, k - 1, j - 1), W + k - 1, ctx); ca_add(ca_mat_entry(A, n - i - 1, j - 1), ca_mat_entry(A, n - i - 1, j - 1), c, ctx); } } for (j = n - i; j <= n - 1; j++) { ca_mul(ca_mat_entry(A, n - i - 1, j - 1), ca_mat_entry(A, n - i - 1, j - 1), W + n - i - 1, ctx); for (k = 1; k < n - i; k++) { ca_mul(c, ca_mat_entry(A, k - 1, j - 1), W + k - 1, ctx); ca_add(ca_mat_entry(A, n - i - 1, j - 1), ca_mat_entry(A, n - i - 1, j - 1), c, ctx); } ca_add(ca_mat_entry(A, n - i - 1, j - 1), ca_mat_entry(A, n - i - 1, j - 1), W + j, ctx); } ca_mul(ca_mat_entry(A, n - i - 1, n - 1), ca_mat_entry(A, n - i - 1, n - 1), W + n - i - 1, ctx); for (k = 1; k < n - i; k++) { ca_mul(c, ca_mat_entry(A, k - 1, n - 1), W + k - 1, ctx); ca_add(ca_mat_entry(A, n - i - 1, n - 1), ca_mat_entry(A, n - i - 1, n - 1), c, ctx); } i++; } ca_one(b + n, ctx); for (i = 1; i <= n; i++) ca_neg(b + i - 1, ca_mat_entry(A, 0, n - i), ctx); _ca_poly_mul(t, p, plen, b, n + 1, ctx); plen += n; _ca_vec_swap(p, t, plen, ctx); cleanup: ca_clear(c, ctx); ca_clear(h, ctx); _ca_vec_clear(t, n_input + 1, ctx); _ca_vec_clear(b, n_input + 1, ctx); _ca_vec_clear(T, n_input, ctx); _ca_vec_clear(V, n_input, ctx); _ca_vec_clear(W, n_input, ctx); return success; } int _ca_mat_charpoly_danilevsky(ca_ptr cp, const ca_mat_t A, ca_ctx_t ctx) { ca_mat_t T; int success; ca_mat_init(T, ca_mat_nrows(A), ca_mat_nrows(A), ctx); ca_mat_set(T, A, ctx); success = _ca_mat_charpoly_danilevsky_inplace(cp, T, ctx); ca_mat_clear(T, ctx); return success; } int ca_mat_charpoly_danilevsky(ca_poly_t cp, const ca_mat_t mat, ca_ctx_t ctx) { ca_poly_fit_length(cp, mat->r + 1, ctx); _ca_poly_set_length(cp, mat->r + 1, ctx); return _ca_mat_charpoly_danilevsky(cp->coeffs, mat, ctx); } calcium-0.4.1/ca_mat/check_equal.c000066400000000000000000000020051407704557200167750ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" truth_t ca_mat_check_equal(const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) { slong i, j; truth_t res, eq; if ((ca_mat_nrows(A) != ca_mat_nrows(B)) || (ca_mat_ncols(A) != ca_mat_ncols(B))) { return T_FALSE; } res = T_TRUE; for (i = 0; i < ca_mat_nrows(A); i++) { for (j = 0; j < ca_mat_ncols(A); j++) { eq = ca_check_equal(ca_mat_entry(A, i, j), ca_mat_entry(B, i, j), ctx); if (eq == T_FALSE) return T_FALSE; if (eq == T_UNKNOWN) res = T_UNKNOWN; } } return res; } calcium-0.4.1/ca_mat/check_is_one.c000066400000000000000000000017131407704557200171470ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" truth_t ca_mat_check_is_one(const ca_mat_t A, ca_ctx_t ctx) { slong i, j; truth_t res, eq; res = T_TRUE; for (i = 0; i < ca_mat_nrows(A); i++) { for (j = 0; j < ca_mat_ncols(A); j++) { if (i == j) eq = ca_check_is_one(ca_mat_entry(A, i, j), ctx); else eq = ca_check_is_zero(ca_mat_entry(A, i, j), ctx); if (eq == T_FALSE) return T_FALSE; if (eq == T_UNKNOWN) res = T_UNKNOWN; } } return res; } calcium-0.4.1/ca_mat/check_is_zero.c000066400000000000000000000015351407704557200173470ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" truth_t ca_mat_check_is_zero(const ca_mat_t A, ca_ctx_t ctx) { slong i, j; truth_t res, eq; res = T_TRUE; for (i = 0; i < ca_mat_nrows(A); i++) { for (j = 0; j < ca_mat_ncols(A); j++) { eq = ca_check_is_zero(ca_mat_entry(A, i, j), ctx); if (eq == T_FALSE) return T_FALSE; if (eq == T_UNKNOWN) res = T_UNKNOWN; } } return res; } calcium-0.4.1/ca_mat/clear.c000066400000000000000000000011171407704557200156220ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_clear(ca_mat_t mat, ca_ctx_t ctx) { if (mat->entries != NULL) { _ca_vec_clear(mat->entries, mat->r * mat->c, ctx); flint_free(mat->rows); } } calcium-0.4.1/ca_mat/companion.c000066400000000000000000000024701407704557200165220ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void _ca_mat_companion(ca_mat_t A, ca_srcptr poly, const ca_t c, ca_ctx_t ctx) { slong i, j, n; n = ca_mat_nrows(A); if (n == 0) return; for (i = 0; i < n - 1; i++) for (j = 0; j < n; j++) ca_set_ui(ca_mat_entry(A, i, j), (i + 1) == j, ctx); for (j = 0; j < n; j++) ca_mul(ca_mat_entry(A, n - 1, j), poly + j, c, ctx); } int ca_mat_companion(ca_mat_t A, const ca_poly_t poly, ca_ctx_t ctx) { ca_t c; int res; slong n = ca_mat_nrows(A); if (n != poly->length - 1 || n != ca_mat_ncols(A)) { return 0; } if (CA_IS_SPECIAL(poly->coeffs + n)) return 0; ca_init(c, ctx); ca_inv(c, poly->coeffs + n, ctx); ca_neg(c, c, ctx); if (CA_IS_SPECIAL(c)) { res = 0; } else { _ca_mat_companion(A, poly->coeffs, c, ctx); res = 1; } ca_clear(c, ctx); return res; } calcium-0.4.1/ca_mat/conj.c000066400000000000000000000015161407704557200154700ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_conj(ca_mat_t B, const ca_mat_t A, ca_ctx_t ctx) { slong i, j; if ((ca_mat_nrows(B) != ca_mat_nrows(A)) || (ca_mat_ncols(B) != ca_mat_ncols(A))) { flint_printf("ca_mat_conj: incompatible dimensions.\n"); flint_abort(); } for (i = 0; i < ca_mat_nrows(A); i++) for (j = 0; j < ca_mat_ncols(A); j++) ca_conj(ca_mat_entry(B, i, j), ca_mat_entry(A, i, j), ctx); } calcium-0.4.1/ca_mat/conj_transpose.c000066400000000000000000000010631407704557200175630ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_conj_transpose(ca_mat_t mat1, const ca_mat_t mat2, ca_ctx_t ctx) { ca_mat_transpose(mat1, mat2, ctx); ca_mat_conj(mat1, mat1, ctx); } calcium-0.4.1/ca_mat/det.c000066400000000000000000000062321407704557200153130ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int _ca_mat_is_fmpq(const ca_mat_t A, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(A); i++) for (j = 0; j < ca_mat_ncols(A); j++) if (!CA_IS_QQ(ca_mat_entry(A, i, j), ctx)) return 0; return 1; } int _ca_mat_fmpq_is_fmpz(const ca_mat_t A, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(A); i++) for (j = 0; j < ca_mat_ncols(A); j++) if (!fmpz_is_one(CA_FMPQ_DENREF(ca_mat_entry(A, i, j)))) return 0; return 1; } ca_field_ptr _ca_mat_same_field(const ca_mat_t A, ca_ctx_t ctx) { ca_field_ptr K, QQ; slong i, j; QQ = ctx->field_qq; K = QQ; for (i = 0; i < ca_mat_nrows(A); i++) { for (j = 0; j < ca_mat_ncols(A); j++) { if (CA_IS_QQ(ca_mat_entry(A, i, j), ctx)) continue; if (CA_IS_SPECIAL(ca_mat_entry(A, i, j))) return NULL; if (K == QQ) K = CA_FIELD(ca_mat_entry(A, i, j), ctx); else if (K != CA_FIELD(ca_mat_entry(A, i, j), ctx)) return NULL; } } return K; } void ca_mat_det(ca_t res, const ca_mat_t A, ca_ctx_t ctx) { slong n; n = ca_mat_nrows(A); if (n != ca_mat_ncols(A)) { flint_printf("ca_mat_det: matrix must be square\n"); flint_abort(); } if (n >= 3 && _ca_mat_is_fmpq(A, ctx)) { if (_ca_mat_fmpq_is_fmpz(A, ctx)) { fmpz_mat_t Zm; fmpz_t det; slong i, j; fmpz_init(det); fmpz_mat_init(Zm, n, n); for (i = 0; i < n; i++) for (j = 0; j < n; j++) *fmpz_mat_entry(Zm, i, j) = *CA_FMPQ_NUMREF(ca_mat_entry(A, i, j)); fmpz_mat_det(det, Zm); flint_free(Zm->rows); flint_free(Zm->entries); ca_set_fmpz(res, det, ctx); fmpz_clear(det); } else { fmpq_mat_t Qm; fmpq_t det; slong i, j; fmpq_init(det); fmpq_mat_init(Qm, n, n); for (i = 0; i < n; i++) for (j = 0; j < n; j++) *fmpq_mat_entry(Qm, i, j) = *CA_FMPQ(ca_mat_entry(A, i, j)); fmpq_mat_det(det, Qm); flint_free(Qm->rows); flint_free(Qm->entries); ca_set_fmpq(res, det, ctx); fmpq_clear(det); } return; } if (n <= 4) { ca_mat_det_cofactor(res, A, ctx); } else { ca_field_ptr K; K = _ca_mat_same_field(A, ctx); if (K != NULL && CA_FIELD_IS_NF(K)) ca_mat_det_lu(res, A, ctx); else ca_mat_det_berkowitz(res, A, ctx); } } calcium-0.4.1/ca_mat/det_bareiss.c000066400000000000000000000017561407704557200170310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_det_bareiss(ca_t res, const ca_mat_t A, ca_ctx_t ctx) { truth_t invertible; slong * P; ca_mat_t T; slong n; n = ca_mat_nrows(A); P = _perm_init(n); ca_mat_init(T, n, n, ctx); invertible = ca_mat_nonsingular_fflu(P, T, res, A, ctx); if (invertible == T_FALSE) { ca_zero(res, ctx); } else if (invertible == T_TRUE) { if (_perm_parity(P, n)) ca_neg(res, res, ctx); } else { ca_unknown(res, ctx); } ca_mat_clear(T, ctx); _perm_clear(P); return invertible != T_UNKNOWN; } calcium-0.4.1/ca_mat/det_berkowitz.c000066400000000000000000000013101407704557200174030ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_det_berkowitz(ca_t res, const ca_mat_t A, ca_ctx_t ctx) { ca_ptr t; t = _ca_vec_init(ca_mat_nrows(A) + 1, ctx); _ca_mat_charpoly(t, A, ctx); ca_swap(res, t, ctx); if (ca_mat_nrows(A) % 2) ca_neg(res, res, ctx); _ca_vec_clear(t, ca_mat_nrows(A) + 1, ctx); } calcium-0.4.1/ca_mat/det_cofactor.c000066400000000000000000000067121407704557200171760ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" static void _ca_mat_det_cofactor_3x3(ca_t t, const ca_mat_t A, ca_ctx_t ctx) { ca_t a, u; ca_init(a, ctx); ca_init(u, ctx); ca_mul (a, ca_mat_entry(A, 1, 0), ca_mat_entry(A, 2, 1), ctx); ca_mul (u, ca_mat_entry(A, 1, 1), ca_mat_entry(A, 2, 0), ctx); ca_sub (a, a, u, ctx); ca_mul (t, a, ca_mat_entry(A, 0, 2), ctx); ca_mul (a, ca_mat_entry(A, 1, 2), ca_mat_entry(A, 2, 0), ctx); ca_mul (u, ca_mat_entry(A, 1, 0), ca_mat_entry(A, 2, 2), ctx); ca_sub (a, a, u, ctx); ca_mul (u, a, ca_mat_entry(A, 0, 1), ctx); ca_add (t, t, u, ctx); ca_mul (a, ca_mat_entry(A, 1, 1), ca_mat_entry(A, 2, 2), ctx); ca_mul (u, ca_mat_entry(A, 1, 2), ca_mat_entry(A, 2, 1), ctx); ca_sub (a, a, u, ctx); ca_mul (u, a, ca_mat_entry(A, 0, 0), ctx); ca_add (t, t, u, ctx); ca_clear(a, ctx); ca_clear(u, ctx); } static void ca_fmms(ca_t x, ca_t tmp, const ca_t a, const ca_t b, const ca_t c, const ca_t d, ca_ctx_t ctx) { ca_mul(tmp, a, b, ctx); ca_mul(x, c, d, ctx); ca_sub(x, tmp, x, ctx); } static void _ca_addmul(ca_t x, ca_t tmp, const ca_t a, const ca_t b, ca_ctx_t ctx) { ca_mul(tmp, a, b, ctx); ca_add(x, x, tmp, ctx); } #define E(i,j) ca_mat_entry(A, i, j) static void _ca_mat_det_cofactor_4x4(ca_t det, const ca_mat_t A, ca_ctx_t ctx) { ca_t a, b, t; ca_init(a, ctx); ca_init(b, ctx); ca_init(t, ctx); ca_fmms(a, t, E(0,3), E(1,2), E(0,2), E(1,3), ctx); ca_fmms(b, t, E(2,1), E(3,0), E(2,0), E(3,1), ctx); ca_mul(det, a, b, ctx); ca_fmms(a, t, E(0,1), E(1,3), E(0,3), E(1,1), ctx); ca_fmms(b, t, E(2,2), E(3,0), E(2,0), E(3,2), ctx); _ca_addmul(det, t, a, b, ctx); ca_fmms(a, t, E(0,2), E(1,1), E(0,1), E(1,2), ctx); ca_fmms(b, t, E(2,3), E(3,0), E(2,0), E(3,3), ctx); _ca_addmul(det, t, a, b, ctx); ca_fmms(a, t, E(0,3), E(1,0), E(0,0), E(1,3), ctx); ca_fmms(b, t, E(2,2), E(3,1), E(2,1), E(3,2), ctx); _ca_addmul(det, t, a, b, ctx); ca_fmms(a, t, E(0,0), E(1,2), E(0,2), E(1,0), ctx); ca_fmms(b, t, E(2,3), E(3,1), E(2,1), E(3,3), ctx); _ca_addmul(det, t, a, b, ctx); ca_fmms(a, t, E(0,1), E(1,0), E(0,0), E(1,1), ctx); ca_fmms(b, t, E(2,3), E(3,2), E(2,2), E(3,3), ctx); _ca_addmul(det, t, a, b, ctx); ca_clear(a, ctx); ca_clear(b, ctx); ca_clear(t, ctx); } #undef E void ca_mat_det_cofactor(ca_t res, const ca_mat_t A, ca_ctx_t ctx) { slong n; n = ca_mat_nrows(A); if (n == 0) { ca_one(res, ctx); } else if (n == 1) { ca_set(res, ca_mat_entry(A, 0, 0), ctx); } else if (n == 2) { ca_t t; ca_init(t, ctx); ca_mul(t, ca_mat_entry(A, 0, 0), ca_mat_entry(A, 1, 1), ctx); ca_mul(res, ca_mat_entry(A, 0, 1), ca_mat_entry(A, 1, 0), ctx); ca_sub(res, t, res, ctx); ca_clear(t, ctx); } else if (n == 3) { _ca_mat_det_cofactor_3x3(res, A, ctx); } else if (n == 4) { _ca_mat_det_cofactor_4x4(res, A, ctx); } else { flint_abort(); } } calcium-0.4.1/ca_mat/det_lu.c000066400000000000000000000021311407704557200160050ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_det_lu(ca_t res, const ca_mat_t A, ca_ctx_t ctx) { truth_t invertible; slong * P; ca_mat_t T; slong i, n; n = ca_mat_nrows(A); P = _perm_init(n); ca_mat_init(T, n, n, ctx); invertible = ca_mat_nonsingular_lu(P, T, A, ctx); if (invertible == T_FALSE) { ca_zero(res, ctx); } else if (invertible == T_TRUE) { ca_one(res, ctx); for (i = 0; i < n; i++) ca_mul(res, res, ca_mat_entry(T, i, i), ctx); if (_perm_parity(P, n)) ca_neg(res, res, ctx); } else { ca_unknown(res, ctx); } ca_mat_clear(T, ctx); _perm_clear(P); return invertible != T_UNKNOWN; } calcium-0.4.1/ca_mat/dft.c000066400000000000000000000035011407704557200153100ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_dft(ca_mat_t res, int type, ca_ctx_t ctx) { ca_ptr w; slong n, r, c, i, j; r = ca_mat_nrows(res); c = ca_mat_ncols(res); n = FLINT_MIN(r, c); if (n == 0) return; w = _ca_vec_init(2 * n, ctx); for (i = 0; i < 2 * n; i++) { if (i == 0) { ca_one(w + i, ctx); } else if (i == 1) { ca_pi_i(w + i, ctx); ca_mul_ui(w + i, w + i, 2, ctx); ca_div_si(w + i, w + i, n, ctx); ca_exp(w + i, w + i, ctx); if (type == 0 || type == 2) ca_inv(w + i, w + i, ctx); } else { ca_mul(w + i, w + i - 1, w + 1, ctx); } } for (i = 0; i < r; i++) { for (j = 0; j < c; j++) { ca_set(ca_mat_entry(res, i, j), w + (i * j) % (2 * n), ctx); } } _ca_vec_clear(w, 2 * n, ctx); if (type == 1) { for (i = 0; i < r; i++) for (j = 0; j < c; j++) ca_div_ui(ca_mat_entry(res, i, j), ca_mat_entry(res, i, j), n, ctx); } else if (type == 2 || type == 3) { ca_t t; ca_init(t, ctx); ca_sqrt_ui(t, n, ctx); ca_inv(t, t, ctx); for (i = 0; i < r; i++) for (j = 0; j < c; j++) ca_mul(ca_mat_entry(res, i, j), ca_mat_entry(res, i, j), t, ctx); ca_clear(t, ctx); } } calcium-0.4.1/ca_mat/diagonalization.c000066400000000000000000000044051407704557200177130ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" truth_t ca_mat_diagonalization_precomp(ca_mat_t D, ca_mat_t P, const ca_mat_t A, const ca_vec_t eigenvalues, const ulong * am, ca_ctx_t ctx) { int success; truth_t result; ca_mat_t AIe, b; slong i, j, k, n; slong nullity, added; n = ca_mat_nrows(A); ca_mat_init(AIe, n, n, ctx); ca_mat_init(b, 0, 0, ctx); result = T_TRUE; ca_mat_zero(D, ctx); added = 0; for (i = 0; i < ca_vec_length(eigenvalues, ctx); i++) { ca_mat_set(AIe, A, ctx); for (j = 0; j < n; j++) ca_sub(ca_mat_entry(AIe, j, j), ca_mat_entry(AIe, j, j), ca_vec_entry(eigenvalues, i), ctx); success = ca_mat_right_kernel(b, AIe, ctx); if (!success) { result = T_UNKNOWN; break; } nullity = ca_mat_ncols(b); if (nullity != am[i]) { result = T_FALSE; break; } for (j = 0; j < am[i]; j++) { ca_set(ca_mat_entry(D, added + j, added + j), ca_vec_entry(eigenvalues, i), ctx); for (k = 0; k < n; k++) ca_set(ca_mat_entry(P, k, added + j), ca_mat_entry(b, k, j), ctx); } added += am[i]; } ca_mat_clear(AIe, ctx); ca_mat_clear(b, ctx); return result; } truth_t ca_mat_diagonalization(ca_mat_t D, ca_mat_t P, const ca_mat_t A, ca_ctx_t ctx) { truth_t result; ca_vec_t eigenvalues; ulong * am; slong n; if (!ca_mat_is_square(A)) return T_FALSE; n = ca_mat_nrows(A); am = flint_malloc(sizeof(ulong) * n); ca_vec_init(eigenvalues, 0, ctx); if (ca_mat_eigenvalues(eigenvalues, am, A, ctx)) { result = ca_mat_diagonalization_precomp(D, P, A, eigenvalues, am, ctx); } else { result = T_UNKNOWN; } ca_vec_clear(eigenvalues, ctx); flint_free(am); return result; } calcium-0.4.1/ca_mat/eigenvalues.c000066400000000000000000000012701407704557200170430ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_eigenvalues(ca_vec_t lambda, ulong * exp, const ca_mat_t mat, ca_ctx_t ctx) { int success; ca_poly_t cp; ca_poly_init(cp, ctx); ca_mat_charpoly(cp, mat, ctx); success = ca_poly_roots(lambda, exp, cp, ctx); ca_poly_clear(cp, ctx); return success; } calcium-0.4.1/ca_mat/exp.c000066400000000000000000000050141407704557200153300ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_exp(ca_mat_t res, const ca_mat_t A, ca_ctx_t ctx) { int success; slong i, j, len, n; ca_mat_t P, Q, J; ca_vec_t lambda, f_lambda; slong num_blocks, num_lambda, offset; slong * block_lambda, * block_size; n = ca_mat_nrows(A); if (n != ca_mat_ncols(A)) return 0; if (n == 0) return 1; success = 1; ca_mat_init(P, n, n, ctx); ca_mat_init(Q, n, n, ctx); ca_mat_init(J, n, n, ctx); block_lambda = flint_malloc(sizeof(slong) * n); block_size = flint_malloc(sizeof(slong) * n); ca_vec_init(lambda, 0, ctx); ca_vec_init(f_lambda, 0, ctx); success = ca_mat_jordan_blocks(lambda, &num_blocks, block_lambda, block_size, A, ctx); if (!success) goto cleanup; num_lambda = ca_vec_length(lambda, ctx); success = ca_mat_jordan_transformation(P, lambda, num_blocks, block_lambda, block_size, A, ctx); if (!success) goto cleanup; if (ca_mat_inv(Q, P, ctx) != T_TRUE) { success = 0; goto cleanup; } /* Evaluate Jordan blocks and build matrix */ ca_vec_set_length(f_lambda, num_lambda, ctx); for (i = 0; i < num_lambda; i++) ca_exp(ca_vec_entry(f_lambda, i), ca_vec_entry(lambda, i), ctx); offset = 0; for (i = 0; i < num_blocks; i++) { len = block_size[i]; ca_set(ca_mat_entry(J, offset, offset), ca_vec_entry(f_lambda, block_lambda[i]), ctx); if (len > 1) { for (j = 1; j < len; j++) ca_div_ui(ca_mat_entry(J, offset, offset + j), ca_mat_entry(J, offset, offset + j - 1), FLINT_MAX(j, 1), ctx); for (j = 1; j < len; j++) _ca_vec_set(ca_mat_entry(J, offset + j, offset + j), ca_mat_entry(J, offset + j - 1, offset + j - 1), len - j, ctx); } offset += block_size[i]; } ca_mat_mul(res, P, J, ctx); ca_mat_mul(res, res, Q, ctx); cleanup: ca_mat_clear(P, ctx); ca_mat_clear(Q, ctx); ca_mat_clear(J, ctx); ca_vec_clear(lambda, ctx); ca_vec_clear(f_lambda, ctx); flint_free(block_lambda); flint_free(block_size); return success; } calcium-0.4.1/ca_mat/fflu.c000066400000000000000000000046011407704557200154710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_fflu(slong * res_rank, slong * P, ca_mat_t LU, ca_t den, const ca_mat_t A, int rank_check, ca_ctx_t ctx) { ca_t d, e; slong i, j, k, m, n, r, rank, row, col; int success; truth_t found_pivot; if (ca_mat_is_empty(A)) { *res_rank = 0; ca_one(den, ctx); return 1; } m = ca_mat_nrows(A); n = ca_mat_ncols(A); ca_mat_set(LU, A, ctx); rank = row = col = 0; if (P != NULL) for (i = 0; i < m; i++) P[i] = i; ca_init(d, ctx); ca_init(e, ctx); success = 1; while (row < m && col < n) { found_pivot = ca_mat_find_pivot(&r, LU, row, m, col, ctx); if (found_pivot == T_UNKNOWN) { success = 0; break; } if (found_pivot == T_FALSE) { if (rank_check) { ca_zero(den, ctx); rank = 0; break; } col++; continue; } rank++; if (r != row) _ca_mat_swap_rows(LU, P, row, r); if (row > 0) ca_inv(d, den, ctx); for (j = row + 1; j < m; j++) { for (k = col + 1; k < n; k++) { ca_mul(ca_mat_entry(LU, j, k), ca_mat_entry(LU, j, k), ca_mat_entry(LU, row, col), ctx); ca_mul(e, ca_mat_entry(LU, j, col), ca_mat_entry(LU, row, k), ctx); ca_sub(ca_mat_entry(LU, j, k), ca_mat_entry(LU, j, k), e, ctx); if (row > 0) ca_mul(ca_mat_entry(LU, j, k), ca_mat_entry(LU, j, k), d, ctx); } /* todo: zero at (j, col) ? */ } ca_set(den, ca_mat_entry(LU, row, col), ctx); row++; col++; } ca_clear(d, ctx); ca_clear(e, ctx); if (success) { if (rank == 0) ca_zero(den, ctx); } if (!success) ca_unknown(den, ctx); *res_rank = rank; return success; } calcium-0.4.1/ca_mat/find_pivot.c000066400000000000000000000054701407704557200167030ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" static truth_t ca_check_is_zero_fast(const ca_t x, ca_ctx_t ctx) { if (CA_IS_QQ(x, ctx)) { return fmpq_is_zero(CA_FMPQ(x)) ? T_TRUE : T_FALSE; } else { return T_UNKNOWN; } } static truth_t ca_check_is_zero_and_simplify(ca_t x, ca_ctx_t ctx) { truth_t res = ca_check_is_zero_fast(x, ctx); if (res == T_UNKNOWN) { res = ca_check_is_zero(x, ctx); if (res == T_TRUE) ca_zero(x, ctx); } return res; } truth_t ca_mat_find_pivot(slong * pivot_row, ca_mat_t mat, slong start_row, slong end_row, slong column, ca_ctx_t ctx) { slong best_row, i; truth_t is_zero; int unknown; if (end_row <= start_row) flint_abort(); /* First find the simplest element that is not trivially zero. With high probability this will actually be nonzero. */ best_row = -1; for (i = start_row; i < end_row; i++) { is_zero = ca_check_is_zero_fast(ca_mat_entry(mat, i, column), ctx); if (is_zero != T_TRUE) { if (best_row == -1 || ca_cmp_repr(ca_mat_entry(mat, i, column), ca_mat_entry(mat, best_row, column), ctx) < 0) { best_row = i; } } } if (best_row != -1) { is_zero = ca_check_is_zero_and_simplify(ca_mat_entry(mat, best_row, column), ctx); if (is_zero == T_FALSE) { *pivot_row = best_row; return T_TRUE; } } /* If the above failed, go through all elements again and do more expensive checks. Todo: 1) support in-place simplifications. 2) consider sorting above and traversing all entries in order of simplicity (not just the simplest element). */ best_row = -1; unknown = 0; for (i = start_row; i < end_row; i++) { is_zero = ca_check_is_zero_and_simplify(ca_mat_entry(mat, i, column), ctx); if (is_zero == T_FALSE) { if (best_row == -1 || ca_cmp_repr(ca_mat_entry(mat, i, column), ca_mat_entry(mat, best_row, column), ctx) < 0) { best_row = i; } } if (is_zero == T_UNKNOWN) unknown = 1; } if (best_row == -1) { *pivot_row = -1; if (unknown) return T_UNKNOWN; else return T_FALSE; } else { *pivot_row = best_row; return T_TRUE; } } calcium-0.4.1/ca_mat/get_fexpr.c000066400000000000000000000051661407704557200165270ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" #include "ca.h" #include "ca_ext.h" #include "ca_mat.h" void _ca_default_variables(fexpr_ptr ext_vars, slong num_ext); void _ca_get_fexpr_given_ext(fexpr_t res, const ca_t x, ulong flags, ca_ext_ptr * ext, slong num_ext, const fexpr_struct * ext_vars, ca_ctx_t ctx); void _ca_all_extensions(ca_ext_ptr ** extensions, slong * length, const ca_t x, ca_ctx_t ctx); void _ca_ext_get_fexpr_given_ext(fexpr_t res, const ca_ext_t x, ulong flags, ca_ext_ptr * ext, slong num_ext, const fexpr_struct * ext_vars, ca_ctx_t ctx); void ca_mat_get_fexpr(fexpr_t res, const ca_mat_t A, ulong flags, ca_ctx_t ctx) { ca_ext_ptr * ext; slong r, c, i, j, num_ext; fexpr_struct * ext_vars; fexpr_struct * where_args; fexpr_struct *rows; fexpr_struct *row; fexpr_t t; ext = NULL; num_ext = 0; r = ca_mat_nrows(A); c = ca_mat_ncols(A); for (i = 0; i < r; i++) for (j = 0; j < c; j++) _ca_all_extensions(&ext, &num_ext, ca_mat_entry(A, i, j), ctx); ext_vars = _fexpr_vec_init(num_ext); fexpr_init(t); _ca_default_variables(ext_vars, num_ext); rows = _fexpr_vec_init(r); row = _fexpr_vec_init(c); for (i = 0; i < r; i++) { for (j = 0; j < c; j++) _ca_get_fexpr_given_ext(row + j, ca_mat_entry(A, i, j), flags, ext, num_ext, ext_vars, ctx); fexpr_set_symbol_builtin(t, FEXPR_Row); fexpr_call_vec(rows + i, t, row, c); } fexpr_set_symbol_builtin(t, FEXPR_Matrix); if (num_ext == 0) { fexpr_call_vec(res, t, rows, r); } else { where_args = _fexpr_vec_init(num_ext + 1); fexpr_call_vec(where_args + 0, t, rows, r); for (i = 0; i < num_ext; i++) { _ca_ext_get_fexpr_given_ext(t, ext[i], flags, ext, num_ext, ext_vars, ctx); fexpr_call_builtin2(where_args + i + 1, FEXPR_Def, ext_vars + i, t); } fexpr_set_symbol_builtin(t, FEXPR_Where); fexpr_call_vec(res, t, where_args, num_ext + 1); _fexpr_vec_clear(where_args, num_ext + 1); } _fexpr_vec_clear(rows, r); _fexpr_vec_clear(row, c); flint_free(ext); fexpr_clear(t); _fexpr_vec_clear(ext_vars, num_ext); } calcium-0.4.1/ca_mat/hilbert.c000066400000000000000000000014231407704557200161650ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_hilbert(ca_mat_t mat, ca_ctx_t ctx) { slong R, C, i, j; R = ca_mat_nrows(mat); C = ca_mat_ncols(mat); for (i = 0; i < R; i++) { for (j = 0; j < C; j++) { ca_one(ca_mat_entry(mat, i, j), ctx); ca_div_ui(ca_mat_entry(mat, i, j), ca_mat_entry(mat, i, j), i + j + 1, ctx); } } } calcium-0.4.1/ca_mat/init.c000066400000000000000000000014371407704557200155040ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_init(ca_mat_t mat, slong r, slong c, ca_ctx_t ctx) { if (r != 0 && c != 0) { slong i; mat->entries = _ca_vec_init(r * c, ctx); mat->rows = (ca_ptr *) flint_malloc(r * sizeof(ca_ptr)); for (i = 0; i < r; i++) mat->rows[i] = mat->entries + i * c; } else mat->entries = NULL; mat->r = r; mat->c = c; } calcium-0.4.1/ca_mat/inlines.c000066400000000000000000000006621407704557200162010ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #define CA_MAT_INLINES_C #include "ca_mat.h" calcium-0.4.1/ca_mat/inv.c000066400000000000000000000026741407704557200153410ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" static truth_t ca_mat_inv_adjugate(ca_mat_t X, const ca_mat_t A, ca_ctx_t ctx) { truth_t success; ca_t det; ca_init(det, ctx); ca_mat_adjugate(X, det, A, ctx); success = ca_check_is_zero(det, ctx); if (success == T_FALSE) { ca_mat_div_ca(X, X, det, ctx); success = T_TRUE; } else if (success == T_TRUE) success = T_FALSE; ca_clear(det, ctx); return success; } truth_t ca_mat_inv(ca_mat_t X, const ca_mat_t A, ca_ctx_t ctx) { ca_field_ptr K; slong n; truth_t success; ca_mat_t T; n = ca_mat_nrows(A); if (n == 0) return T_TRUE; if (n <= 4) return ca_mat_inv_adjugate(X, A, ctx); K = _ca_mat_same_field(A, ctx); if (K != NULL && (CA_FIELD_IS_QQ(K) || CA_FIELD_IS_NF(K))) { ca_mat_init(T, n, n, ctx); ca_mat_one(T, ctx); success = ca_mat_nonsingular_solve_lu(X, A, T, ctx); ca_mat_clear(T, ctx); return success; } else { return ca_mat_inv_adjugate(X, A, ctx); } } calcium-0.4.1/ca_mat/jordan_blocks.c000066400000000000000000000103211407704557200173430ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_set_jordan_blocks(ca_mat_t mat, const ca_vec_t lambda, slong num_blocks, slong * block_lambda, slong * block_size, ca_ctx_t ctx) { slong i, j, n, count; n = ca_mat_nrows(mat); if (n != ca_mat_ncols(mat)) { flint_printf("ca_mat_set_jordan_blocks: matrix must be square\n"); flint_abort(); } count = 0; for (i = 0; i < num_blocks; i++) count += block_size[i]; if (count != n) { flint_printf("ca_mat_set_jordan_blocks: sum of block sizes does not agree with size of output matrix\n"); flint_abort(); } ca_mat_zero(mat, ctx); count = 0; for (i = 0; i < num_blocks; i++) { for (j = 0; j < block_size[i]; j++) { ca_set(ca_mat_entry(mat, count + j, count + j), ca_vec_entry(lambda, block_lambda[i]), ctx); if (j < block_size[i] - 1) ca_one(ca_mat_entry(mat, count + j, count + j + 1), ctx); } count += block_size[i]; } } int ca_mat_jordan_blocks(ca_vec_t lambda, slong * num_blocks, slong * block_lambda, slong * block_size, const ca_mat_t A, ca_ctx_t ctx) { slong i, j, k, n; slong * ranks, * diagram; slong ranks_len, rank; ulong * exp; int success; n = ca_mat_nrows(A); if (n != ca_mat_ncols(A)) { flint_printf("ca_mat_jordan_blocks: matrix must be square\n"); flint_abort(); } exp = flint_malloc(sizeof(ulong) * n); ranks = flint_malloc(sizeof(slong) * (n + 1)); diagram = flint_malloc(sizeof(slong) * n); success = ca_mat_eigenvalues(lambda, exp, A, ctx); if (success) { *num_blocks = 0; for (i = 0; success && i < ca_vec_length(lambda, ctx); i++) { if (exp[i] == 1) { block_lambda[*num_blocks] = i; block_size[*num_blocks] = 1; *num_blocks += 1; } else { ca_mat_t B, C; ca_mat_init(B, n, n, ctx); ca_mat_init(C, n, n, ctx); for (j = 0; j < n; j++) for (k = 0; k < n; k++) if (j == k) ca_sub(ca_mat_entry(B, j, j), ca_mat_entry(A, j, j), ca_vec_entry(lambda, i), ctx); else ca_set(ca_mat_entry(B, j, k), ca_mat_entry(A, j, k), ctx); ca_mat_set(C, B, ctx); success = ca_mat_rank(&rank, C, ctx); ranks_len = 2; ranks[0] = n; ranks[1] = rank; j = 0; while (success && (ranks[j] > ranks[j + 1] && ranks[j + 1] + exp[i] > n)) { ca_mat_mul(C, B, C, ctx); success = ca_mat_rank(&rank, C, ctx); ranks[ranks_len] = rank; j++; ranks_len++; } if (success) { /* Ferrer's diagram of an integer partition */ for (j = 0; j < ranks_len - 1; j++) diagram[j] = ranks[j] - ranks[j + 1]; /* Transpose Ferrer's diagram */ for (j = 1; j <= diagram[0]; j++) { slong c = 0; for (k = 0; k < ranks_len - 1; k++) c += (diagram[k] >= j); block_lambda[*num_blocks] = i; block_size[*num_blocks] = c; *num_blocks += 1; } } ca_mat_clear(B, ctx); ca_mat_clear(C, ctx); } } } flint_free(exp); flint_free(ranks); flint_free(diagram); return success; } calcium-0.4.1/ca_mat/jordan_form.c000066400000000000000000000026311407704557200170360ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_jordan_form(ca_mat_t J, ca_mat_t P, const ca_mat_t A, ca_ctx_t ctx) { ca_vec_t lambda; slong n; slong num_blocks, * block_size, * block_lambda; int success; n = ca_mat_nrows(A); if (J == A || P == A) { ca_mat_t T; ca_mat_init(T, n, n, ctx); ca_mat_set(T, A, ctx); success = ca_mat_jordan_form(J, P, T, ctx); ca_mat_clear(T, ctx); return success; } ca_vec_init(lambda, 0, ctx); block_lambda = flint_malloc(sizeof(slong) * n); block_size = flint_malloc(sizeof(slong) * n); success = ca_mat_jordan_blocks(lambda, &num_blocks, block_lambda, block_size, A, ctx); if (success && P != NULL) success = ca_mat_jordan_transformation(P, lambda, num_blocks, block_lambda, block_size, A, ctx); if (success) ca_mat_set_jordan_blocks(J, lambda, num_blocks, block_lambda, block_size, ctx); ca_vec_clear(lambda, ctx); flint_free(block_lambda); flint_free(block_size); return success; } calcium-0.4.1/ca_mat/jordan_transformation.c000066400000000000000000000227561407704557200211530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" /* The algorithm is taken from jordan_form() in Sage */ /* Find a row vector v in the row span of V but not in the row span of W. Returns the index of such a vector. Returns -1 on failure. */ static slong vector_in_difference(const ca_mat_t V, const ca_mat_t W, ca_ctx_t ctx) { ca_mat_t U; ca_ptr v; ca_t t, u; slong i, j, k, l, n, found, rank; truth_t is_zero; if (ca_mat_nrows(V) == 0) return -1; if (ca_mat_nrows(W) == 0) return 0; n = ca_mat_ncols(W); found = -1; ca_mat_init(U, ca_mat_nrows(W), n, ctx); v = _ca_vec_init(n, ctx); ca_init(t, ctx); ca_init(u, ctx); if (ca_mat_rref(&rank, U, W, ctx)) { for (i = 0; i < ca_mat_nrows(V); i++) /* for candidate v in V */ { /* Copy of v for reduction */ _ca_vec_set(v, ca_mat_entry(V, i, 0), n, ctx); /* Reduce v by the rows in W */ for (j = 0; j < rank; j++) /* for each w in W */ { for (k = 0; k < n; k++) /* find pivot element in w */ { is_zero = ca_check_is_zero(ca_mat_entry(U, j, k), ctx); if (is_zero == T_UNKNOWN) goto cleanup; /* reduce by this row */ if (is_zero == T_FALSE) { ca_div(t, v + k, ca_mat_entry(U, j, k), ctx); for (l = 0; l < n; l++) { if (l == k) ca_zero(v + l, ctx); else { ca_mul(u, t, ca_mat_entry(U, j, l), ctx); ca_sub(v + l, v + l, u, ctx); } } break; } } } is_zero = _ca_vec_check_is_zero(v, n, ctx); if (is_zero == T_UNKNOWN) goto cleanup; if (is_zero == T_FALSE) { found = i; break; } } } cleanup: ca_mat_clear(U, ctx); _ca_vec_clear(v, n, ctx); ca_clear(t, ctx); ca_clear(u, ctx); return found; } /* note: doesn't support aliasing */ static void _ca_mat_mul_vec(ca_ptr res, const ca_mat_t mat, ca_srcptr v, ca_ctx_t ctx) { slong i; for (i = 0; i < ca_mat_nrows(mat); i++) { ca_dot(res + i, NULL, 0, ca_mat_entry(mat, i, 0), 1, v, 1, ca_mat_ncols(mat), ctx); } } static void ca_mat_transpose_resize(ca_mat_t B, const ca_mat_t A, ca_ctx_t ctx) { ca_mat_t T; ca_mat_init(T, ca_mat_ncols(A), ca_mat_nrows(A), ctx); ca_mat_transpose(T, A, ctx); ca_mat_swap(B, T, ctx); ca_mat_clear(T, ctx); } /* todo: special-case num_lambda == n (diagonalization) */ /* todo: also, for each vector */ /* todo: aliasing */ int ca_mat_jordan_transformation(ca_mat_t mat, const ca_vec_t lambda, slong num_blocks, slong * block_lambda, slong * block_size, const ca_mat_t A, ca_ctx_t ctx) { slong num_lambda, i, j, k, l, m, n, output_block, column_offset; slong *sizes, *counts; ca_mat_t B, Y, V1, V2, V1ker, V2ker; slong size, num_sizes, count, y_rows, v_index; int * written; int success; n = ca_mat_nrows(A); if (n == 0) return 1; num_lambda = ca_vec_length(lambda, ctx); /* Special-case diagonalization with distinct eigenvalues. */ /* TODO: also special-case eigenvalues with multiplicity 1 below. */ if (num_lambda == n) { success = 1; ca_mat_init(B, n, n, ctx); ca_mat_init(Y, 0, 0, ctx); for (i = 0; i < n; i++) { /* B = A - lambda */ for (j = 0; j < n; j++) for (k = 0; k < n; k++) if (j == k) ca_sub(ca_mat_entry(B, j, j), ca_mat_entry(A, j, j), ca_vec_entry(lambda, block_lambda[i]), ctx); else ca_set(ca_mat_entry(B, j, k), ca_mat_entry(A, j, k), ctx); success = ca_mat_right_kernel(Y, B, ctx); if (!success) break; if (ca_mat_ncols(Y) != 1) abort(); for (j = 0; j < n; j++) ca_set(ca_mat_entry(mat, j, i), ca_mat_entry(Y, j, 0), ctx); } ca_mat_clear(B, ctx); ca_mat_clear(Y, ctx); return success; } sizes = flint_malloc(sizeof(slong) * n); counts = flint_malloc(sizeof(slong) * n); written = flint_calloc(num_blocks, sizeof(int)); ca_mat_init(B, n, n, ctx); ca_mat_init(Y, 0, n, ctx); ca_mat_init(V1, n, n, ctx); ca_mat_init(V2, n, n, ctx); ca_mat_init(V1ker, 0, 0, ctx); ca_mat_init(V2ker, 0, 0, ctx); success = 1; for (i = 0; i < num_lambda; i++) { /* B = A - lambda */ for (j = 0; j < n; j++) for (k = 0; k < n; k++) if (j == k) ca_sub(ca_mat_entry(B, j, j), ca_mat_entry(A, j, j), ca_vec_entry(lambda, i), ctx); else ca_set(ca_mat_entry(B, j, k), ca_mat_entry(A, j, k), ctx); /* Group blocks as (block size, count) */ /* Todo: does this need to be sorted? */ num_sizes = 0; for (j = 0; j < num_blocks; j++) { if (block_lambda[j] == i) { for (k = 0; k < num_sizes; k++) { if (sizes[k] == block_size[j]) { counts[k]++; break; } } if (k == num_sizes) { sizes[num_sizes] = block_size[j]; counts[num_sizes] = 1; num_sizes++; } } } /* Y = matrix of row vectors spanning the Jordan chains for this eigenvalue. */ ca_mat_clear(Y, ctx); ca_mat_init(Y, n, n, ctx); y_rows = 0; /* Iterate over (block size, count) */ for (j = 0; j < num_sizes; j++) { size = sizes[j]; count = counts[j]; if (size == 0) flint_abort(); /* Find elements in ker(B^size) - ker(B^(size-1)) */ ca_mat_pow_ui_binexp(V2, B, size - 1, ctx); ca_mat_mul(V1, B, V2, ctx); success = ca_mat_right_kernel(V1ker, V1, ctx); if (!success) goto cleanup; success = ca_mat_right_kernel(V2ker, V2, ctx); if (!success) goto cleanup; /* rows instead of columns */ ca_mat_transpose_resize(V1ker, V1ker, ctx); ca_mat_transpose_resize(V2ker, V2ker, ctx); for (k = 0; k < count; k++) { /* Concatenate V2ker with Y */ ca_mat_t V2kerY; ca_mat_init(V2kerY, ca_mat_nrows(V2ker) + y_rows, n, ctx); for (m = 0; m < ca_mat_nrows(V2ker); m++) _ca_vec_set(ca_mat_entry(V2kerY, m, 0), ca_mat_entry(V2ker, m, 0), n, ctx); for (m = 0; m < y_rows; m++) _ca_vec_set(ca_mat_entry(V2kerY, ca_mat_nrows(V2ker) + m, 0), ca_mat_entry(Y, m, 0), n, ctx); v_index = vector_in_difference(V1ker, V2kerY, ctx); ca_mat_clear(V2kerY, ctx); if (v_index == -1) { success = 0; goto cleanup; } /* Position in output matrix to write chain. */ column_offset = 0; output_block = 0; while (1) { if (block_lambda[output_block] == i && block_size[output_block] == size && !written[output_block]) { written[output_block] = 1; break; } else { column_offset += block_size[output_block]; output_block++; } } /* chain = [v, B*v, ..., B^(size-1)*v] */ _ca_vec_set(ca_mat_entry(Y, y_rows, 0), ca_mat_entry(V1ker, v_index, 0), n, ctx); for (m = 1; m < size; m++) { _ca_mat_mul_vec(ca_mat_entry(Y, y_rows + m, 0), B, ca_mat_entry(Y, y_rows + m - 1, 0), ctx); } y_rows += size; /* Insert chain in the output matrix */ for (m = 0; m < size; m++) { for (l = 0; l < n; l++) ca_set(ca_mat_entry(mat, l, column_offset + m), ca_mat_entry(Y, y_rows - 1 - m, l), ctx); } } } } cleanup: flint_free(sizes); flint_free(counts); ca_mat_clear(B, ctx); ca_mat_clear(Y, ctx); ca_mat_clear(V1, ctx); ca_mat_clear(V2, ctx); ca_mat_clear(V1ker, ctx); ca_mat_clear(V2ker, ctx); flint_free(written); return success; } calcium-0.4.1/ca_mat/log.c000066400000000000000000000065271407704557200153270ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" truth_t ca_mat_log(ca_mat_t res, const ca_mat_t A, ca_ctx_t ctx) { truth_t result, is_zero; int success; slong i, j, len, n; ca_mat_t P, Q, J; ca_t t; ca_vec_t lambda, f_lambda; slong num_blocks, num_lambda, offset; slong * block_lambda, * block_size; n = ca_mat_nrows(A); if (n != ca_mat_ncols(A)) return T_FALSE; if (n == 0) return T_TRUE; result = T_TRUE; ca_mat_init(P, n, n, ctx); ca_mat_init(Q, n, n, ctx); ca_mat_init(J, n, n, ctx); ca_init(t, ctx); block_lambda = flint_malloc(sizeof(slong) * n); block_size = flint_malloc(sizeof(slong) * n); ca_vec_init(lambda, 0, ctx); ca_vec_init(f_lambda, 0, ctx); success = ca_mat_jordan_blocks(lambda, &num_blocks, block_lambda, block_size, A, ctx); if (!success) { result = T_UNKNOWN; goto cleanup; } num_lambda = ca_vec_length(lambda, ctx); /* Zero must not be an eigenvalue */ for (i = 0; i < num_lambda; i++) { is_zero = ca_check_is_zero(ca_vec_entry(lambda, i), ctx); if (is_zero == T_UNKNOWN) { result = T_UNKNOWN; goto cleanup; } if (is_zero == T_TRUE) { result = T_FALSE; goto cleanup; } } success = ca_mat_jordan_transformation(P, lambda, num_blocks, block_lambda, block_size, A, ctx); if (!success) { result = T_UNKNOWN; goto cleanup; } result = ca_mat_inv(Q, P, ctx); if (result != T_TRUE) goto cleanup; /* Evaluate Jordan blocks and build matrix */ ca_vec_set_length(f_lambda, num_lambda, ctx); for (i = 0; i < num_lambda; i++) ca_log(ca_vec_entry(f_lambda, i), ca_vec_entry(lambda, i), ctx); offset = 0; for (i = 0; i < num_blocks; i++) { len = block_size[i]; ca_set(ca_mat_entry(J, offset, offset), ca_vec_entry(f_lambda, block_lambda[i]), ctx); if (len > 1) { ca_inv(t, ca_vec_entry(lambda, block_lambda[i]), ctx); ca_set(ca_mat_entry(J, offset, offset + 1), t, ctx); ca_neg(t, t, ctx); for (j = 2; j < len; j++) ca_mul(ca_mat_entry(J, offset, offset + j), ca_mat_entry(J, offset, offset + j - 1), t, ctx); for (j = 2; j < len; j++) ca_div_ui(ca_mat_entry(J, offset, offset + j), ca_mat_entry(J, offset, offset + j), j, ctx); for (j = 1; j < len; j++) _ca_vec_set(ca_mat_entry(J, offset + j, offset + j), ca_mat_entry(J, offset + j - 1, offset + j - 1), len - j, ctx); } offset += block_size[i]; } ca_mat_mul(res, P, J, ctx); ca_mat_mul(res, res, Q, ctx); cleanup: ca_mat_clear(P, ctx); ca_mat_clear(Q, ctx); ca_mat_clear(J, ctx); ca_vec_clear(lambda, ctx); ca_vec_clear(f_lambda, ctx); ca_clear(t, ctx); flint_free(block_lambda); flint_free(block_size); return result; } calcium-0.4.1/ca_mat/lu.c000066400000000000000000000011021407704557200151460ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_lu(slong * rank, slong * P, ca_mat_t LU, const ca_mat_t A, int rank_check, ca_ctx_t ctx) { return ca_mat_lu_recursive(rank, P, LU, A, rank_check, ctx); } calcium-0.4.1/ca_mat/lu_classical.c000066400000000000000000000036101407704557200171720ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_lu_classical(slong * res_rank, slong * P, ca_mat_t LU, const ca_mat_t A, int rank_check, ca_ctx_t ctx) { ca_t d, e; ca_ptr * a; slong i, j, m, n, r, rank, row, col; int success; truth_t found_pivot; if (ca_mat_is_empty(A)) { *res_rank = 0; return 1; } m = ca_mat_nrows(A); n = ca_mat_ncols(A); ca_mat_set(LU, A, ctx); a = LU->rows; rank = row = col = 0; for (i = 0; i < m; i++) P[i] = i; ca_init(d, ctx); ca_init(e, ctx); success = 1; while (row < m && col < n) { found_pivot = ca_mat_find_pivot(&r, LU, row, m, col, ctx); if (found_pivot == T_UNKNOWN) { success = 0; break; } if (found_pivot == T_FALSE) { if (rank_check) { rank = 0; break; } col++; continue; } rank++; if (r != row) _ca_mat_swap_rows(LU, P, row, r); ca_inv(d, a[row] + col, ctx); for (j = row + 1; j < m; j++) { ca_mul(e, a[j] + col, d, ctx); ca_neg(e, e, ctx); _ca_vec_scalar_addmul_ca(a[j] + col + 1, a[row] + col + 1, n - col - 1, e, ctx); ca_zero(a[j] + col, ctx); ca_neg(a[j] + rank - 1, e, ctx); } row++; col++; } ca_clear(d, ctx); ca_clear(e, ctx); *res_rank = rank; return success; } calcium-0.4.1/ca_mat/lu_recursive.c000066400000000000000000000063031407704557200172450ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" static void _apply_permutation(slong * AP, ca_mat_t A, slong * P, slong n, slong offset) { if (n != 0) { ca_struct ** Atmp; slong *APtmp; slong i; Atmp = flint_malloc(sizeof(ca_mat_struct *) * n); APtmp = flint_malloc(sizeof(slong) * n); for (i = 0; i < n; i++) Atmp[i] = A->rows[P[i] + offset]; for (i = 0; i < n; i++) A->rows[i + offset] = Atmp[i]; for (i = 0; i < n; i++) APtmp[i] = AP[P[i] + offset]; for (i = 0; i < n; i++) AP[i + offset] = APtmp[i]; flint_free(Atmp); flint_free(APtmp); } } int ca_mat_lu_recursive(slong * rank, slong * P, ca_mat_t LU, const ca_mat_t A, int rank_check, ca_ctx_t ctx) { slong i, j, m, n, r1, r2, n1; ca_mat_t A0, A1, A00, A01, A10, A11; slong *P1; int success; m = A->r; n = A->c; if (m < 4 || n < 4) return ca_mat_lu_classical(rank, P, LU, A, rank_check, ctx); if (LU != A) ca_mat_set(LU, A, ctx); n1 = n / 2; for (i = 0; i < m; i++) P[i] = i; P1 = flint_malloc(sizeof(slong) * m); ca_mat_window_init(A0, LU, 0, 0, m, n1, ctx); ca_mat_window_init(A1, LU, 0, n1, m, n, ctx); success = ca_mat_lu_recursive(&r1, P1, A0, A0, rank_check, ctx); if (!success || (rank_check && (r1 != n1))) { success = 0; goto cleanup1; } if (r1 != 0) { _apply_permutation(P, LU, P1, m, 0); } ca_mat_window_init(A00, LU, 0, 0, r1, r1, ctx); ca_mat_window_init(A10, LU, r1, 0, m, r1, ctx); ca_mat_window_init(A01, LU, 0, n1, r1, n, ctx); ca_mat_window_init(A11, LU, r1, n1, m, n, ctx); if (r1 != 0) { ca_mat_t T; ca_mat_init(T, ca_mat_nrows(A10), ca_mat_ncols(A01), ctx); ca_mat_solve_tril(A01, A00, A01, 1, ctx); ca_mat_mul(T, A10, A01, ctx); ca_mat_sub(A11, A11, T, ctx); ca_mat_clear(T, ctx); } success = ca_mat_lu_recursive(&r2, P1, A11, A11, rank_check, ctx); if (!success || (rank_check && (r1 + r2 < FLINT_MIN(m, n)))) { r1 = r2 = 0; goto cleanup2; } _apply_permutation(P, LU, P1, m - r1, r1); /* Compress L */ if (r1 != n1) { for (i = 0; i < m - r1; i++) { ca_struct * row = LU->rows[r1 + i]; for (j = 0; j < FLINT_MIN(i, r2) ; j++) { ca_set(row + r1 + j, row + n1 + j, ctx); ca_zero(row + n1 + j, ctx); } } } cleanup2: ca_mat_window_clear(A00, ctx); ca_mat_window_clear(A10, ctx); ca_mat_window_clear(A01, ctx); ca_mat_window_clear(A11, ctx); cleanup1: flint_free(P1); ca_mat_window_clear(A0, ctx); ca_mat_window_clear(A1, ctx); *rank = r1 + r2; return success; } calcium-0.4.1/ca_mat/mul.c000066400000000000000000000156001407704557200153330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_is_fmpq_mat(const ca_mat_t A, ca_ctx_t ctx) { slong ar, ac, i, j; ar = ca_mat_nrows(A); ac = ca_mat_ncols(A); for (i = 0; i < ar; i++) for (j = 0; j < ac; j++) if (!CA_IS_QQ(ca_mat_entry(A, i, j), ctx)) return 0; return 1; } int ca_fmpq_mat_is_fmpz_mat(const ca_mat_t A, ca_ctx_t ctx) { slong ar, ac, i, j; ar = ca_mat_nrows(A); ac = ca_mat_ncols(A); for (i = 0; i < ar; i++) for (j = 0; j < ac; j++) if (!fmpz_is_one(CA_FMPQ_DENREF(ca_mat_entry(A, i, j)))) return 0; return 1; } ca_field_ptr _ca_mat_same_field2(const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) { ca_field_ptr K; ca_field_ptr QQ; slong i, j; QQ = ctx->field_qq; K = QQ; for (i = 0; i < ca_mat_nrows(A); i++) { for (j = 0; j < ca_mat_ncols(A); j++) { if (CA_IS_QQ(ca_mat_entry(A, i, j), ctx)) continue; if (CA_IS_SPECIAL(ca_mat_entry(A, i, j))) return NULL; if (K == QQ) K = CA_FIELD(ca_mat_entry(A, i, j), ctx); else if (K != CA_FIELD(ca_mat_entry(A, i, j), ctx)) return NULL; } } if (B != NULL) { for (i = 0; i < ca_mat_nrows(B); i++) { for (j = 0; j < ca_mat_ncols(B); j++) { if (CA_IS_QQ(ca_mat_entry(B, i, j), ctx)) continue; if (CA_IS_SPECIAL(ca_mat_entry(B, i, j))) return NULL; if (K == QQ) K = CA_FIELD(ca_mat_entry(B, i, j), ctx); else if (K != CA_FIELD(ca_mat_entry(B, i, j), ctx)) return NULL; } } } return K; } void ca_mat_mul(ca_mat_t C, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) { slong ar, ac, br, bc, i, j; ca_field_ptr K; ar = ca_mat_nrows(A); ac = ca_mat_ncols(A); br = ca_mat_nrows(B); bc = ca_mat_ncols(B); if (ac != br || ar != ca_mat_nrows(C) || bc != ca_mat_ncols(C)) { flint_printf("ca_mat_mul: incompatible dimensions\n"); flint_abort(); } if (br == 0) { ca_mat_zero(C, ctx); return; } if (A == C || B == C) { ca_mat_t T; ca_mat_init(T, ar, bc, ctx); ca_mat_mul(T, A, B, ctx); ca_mat_swap(T, C, ctx); ca_mat_clear(T, ctx); return; } /* Multiply integer and rational matrices efficiently */ if (br >= 3 && ca_mat_is_fmpq_mat(A, ctx) && ca_mat_is_fmpq_mat(B, ctx)) { fmpq_mat_t AQ, BQ, CQ; fmpz_mat_t AZ, BZ, CZ; int Aintegral, Bintegral; Aintegral = Bintegral = 0; Aintegral = ca_fmpq_mat_is_fmpz_mat(A, ctx); Bintegral = ca_fmpq_mat_is_fmpz_mat(B, ctx); if (Aintegral) { fmpz_mat_init(AZ, ar, ac); for (i = 0; i < ar; i++) for (j = 0; j < ac; j++) *fmpz_mat_entry(AZ, i, j) = *CA_FMPQ_NUMREF(ca_mat_entry(A, i, j)); } else { fmpq_mat_init(AQ, ar, ac); for (i = 0; i < ar; i++) for (j = 0; j < ac; j++) *fmpq_mat_entry(AQ, i, j) = *CA_FMPQ(ca_mat_entry(A, i, j)); } if (Bintegral) { fmpz_mat_init(BZ, br, bc); for (i = 0; i < br; i++) for (j = 0; j < bc; j++) *fmpz_mat_entry(BZ, i, j) = *CA_FMPQ_NUMREF(ca_mat_entry(B, i, j)); } else { fmpq_mat_init(BQ, br, bc); for (i = 0; i < br; i++) for (j = 0; j < bc; j++) *fmpq_mat_entry(BQ, i, j) = *CA_FMPQ(ca_mat_entry(B, i, j)); } if (Aintegral && Bintegral) { fmpz_mat_init(CZ, ar, bc); for (i = 0; i < ar; i++) { for (j = 0; j < bc; j++) { _ca_make_fmpq(ca_mat_entry(C, i, j), ctx); fmpz_one(CA_FMPQ_DENREF(ca_mat_entry(C, i, j))); *fmpz_mat_entry(CZ, i, j) = *CA_FMPQ_NUMREF(ca_mat_entry(C, i, j)); } } } else { fmpq_mat_init(CQ, ar, bc); for (i = 0; i < ar; i++) { for (j = 0; j < bc; j++) { _ca_make_fmpq(ca_mat_entry(C, i, j), ctx); *fmpq_mat_entry(CQ, i, j) = *CA_FMPQ(ca_mat_entry(C, i, j)); } } } if (Aintegral && Bintegral) { fmpz_mat_mul(CZ, AZ, BZ); for (i = 0; i < ar; i++) for (j = 0; j < bc; j++) *CA_FMPQ_NUMREF(ca_mat_entry(C, i, j)) = *fmpz_mat_entry(CZ, i, j); flint_free(AZ->entries); flint_free(AZ->rows); flint_free(BZ->entries); flint_free(BZ->rows); flint_free(CZ->entries); flint_free(CZ->rows); } else { if (Bintegral) { fmpq_mat_mul_fmpz_mat(CQ, AQ, BZ); } else if (Aintegral) { fmpq_mat_mul_r_fmpz_mat(CQ, AZ, BQ); } else { fmpq_mat_mul(CQ, AQ, BQ); } for (i = 0; i < ar; i++) for (j = 0; j < bc; j++) *CA_FMPQ(ca_mat_entry(C, i, j)) = *fmpq_mat_entry(CQ, i, j); if (Aintegral) { flint_free(AZ->entries); flint_free(AZ->rows); } else { flint_free(AQ->entries); flint_free(AQ->rows); } if (Bintegral) { flint_free(BZ->entries); flint_free(BZ->rows); } else { flint_free(BQ->entries); flint_free(BQ->rows); } flint_free(CQ->entries); flint_free(CQ->rows); } return; } /* Multiply over number field */ /* Todo: probably needs some tuning for degree and bit size */ if (br >= 4 && ar >= 3 && bc >= 3) { K = _ca_mat_same_field2(A, B, ctx); if (K != NULL && CA_FIELD_IS_NF(K)) { ca_mat_mul_same_nf(C, A, B, K, ctx); return; } } ca_mat_mul_classical(C, A, B, ctx); } calcium-0.4.1/ca_mat/mul_classical.c000066400000000000000000000031151407704557200173470ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_mul_classical(ca_mat_t C, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) { slong ar, ac, br, bc, i, j, k; ca_t t; ar = ca_mat_nrows(A); ac = ca_mat_ncols(A); br = ca_mat_nrows(B); bc = ca_mat_ncols(B); if (ac != br || ar != ca_mat_nrows(C) || bc != ca_mat_ncols(C)) { flint_printf("ca_mat_mul_classical: incompatible dimensions\n"); flint_abort(); } if (br == 0) { ca_mat_zero(C, ctx); return; } if (A == C || B == C) { ca_mat_t T; ca_mat_init(T, ar, bc, ctx); ca_mat_mul(T, A, B, ctx); ca_mat_swap(T, C, ctx); ca_mat_clear(T, ctx); return; } ca_init(t, ctx); for (i = 0; i < ar; i++) { for (j = 0; j < bc; j++) { ca_mul(ca_mat_entry(C, i, j), ca_mat_entry(A, i, 0), ca_mat_entry(B, 0, j), ctx); for (k = 1; k < br; k++) { ca_mul(t, ca_mat_entry(A, i, k), ca_mat_entry(B, k, j), ctx); ca_add(ca_mat_entry(C, i, j), ca_mat_entry(C, i, j), t, ctx); } } } ca_clear(t, ctx); } calcium-0.4.1/ca_mat/mul_same_nf.c000066400000000000000000000165331407704557200170310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "flint/fmpz_poly_mat.h" #include "ca_mat.h" static const fmpz * _nf_denref(const nf_elem_t a, const nf_t nf) { if (nf->flag & NF_LINEAR) return LNF_ELEM_DENREF(a); else if (nf->flag & NF_QUADRATIC) return QNF_ELEM_DENREF(a); else return NF_ELEM_DENREF(a); } static void _nf_elem_get_fmpz_poly_lcm(fmpz_poly_t pol, fmpz_t t, const nf_elem_t a, const fmpz_t lcm, const nf_t nf) { fmpz_divexact(t, lcm, _nf_denref(a, nf)); if (nf->flag & NF_LINEAR) { fmpz_mul(t, t, LNF_ELEM_NUMREF(a)); fmpz_poly_set_fmpz(pol, t); } else if (nf->flag & NF_QUADRATIC) { const fmpz * const anum = QNF_ELEM_NUMREF(a); fmpz_poly_fit_length(pol, 2); _fmpz_poly_set_length(pol, 2); _fmpz_vec_scalar_mul_fmpz(pol->coeffs, anum, 2, t); _fmpz_poly_normalise(pol); } else { fmpz_poly_fit_length(pol, NF_ELEM(a)->length); _fmpz_poly_set_length(pol, NF_ELEM(a)->length); _fmpz_vec_scalar_mul_fmpz(pol->coeffs, NF_ELEM(a)->coeffs, NF_ELEM(a)->length, t); } } static int get_lcm_rowwise(fmpz * Aden, const ca_mat_t A, ca_field_t K, slong bits_limit, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(A); i++) { fmpz_one(Aden + i); for (j = 0; j < ca_mat_ncols(A); j++) { if (CA_IS_QQ(ca_mat_entry(A, i, j), ctx)) fmpz_lcm(Aden + i, Aden + i, CA_FMPQ_DENREF(ca_mat_entry(A, i, j))); else fmpz_lcm(Aden + i, Aden + i, _nf_denref(CA_NF_ELEM(ca_mat_entry(A, i, j)), CA_FIELD_NF(K))); if (fmpz_bits(Aden + i) > bits_limit) return 0; } } return 1; } static int get_lcm_colwise(fmpz * Aden, const ca_mat_t A, ca_field_t K, slong bits_limit, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_ncols(A); i++) { fmpz_one(Aden + i); for (j = 0; j < ca_mat_nrows(A); j++) { if (CA_IS_QQ(ca_mat_entry(A, j, i), ctx)) fmpz_lcm(Aden + i, Aden + i, CA_FMPQ_DENREF(ca_mat_entry(A, j, i))); else fmpz_lcm(Aden + i, Aden + i, _nf_denref(CA_NF_ELEM(ca_mat_entry(A, j, i)), CA_FIELD_NF(K))); if (fmpz_bits(Aden + i) > bits_limit) return 0; } } return 1; } static void get_mat_rowwise(fmpz_poly_mat_t Aclear, const ca_mat_t A, const fmpz * Aden, ca_field_t K, ca_ctx_t ctx) { slong i, j; fmpz_t t; fmpz_init(t); for (i = 0; i < ca_mat_nrows(A); i++) { for (j = 0; j < ca_mat_ncols(A); j++) { if (CA_IS_QQ(ca_mat_entry(A, i, j), ctx)) { fmpz_divexact(t, Aden + i, CA_FMPQ_DENREF(ca_mat_entry(A, i, j))); fmpz_mul(t, t, CA_FMPQ_NUMREF(ca_mat_entry(A, i, j))); fmpz_poly_set_fmpz(fmpz_poly_mat_entry(Aclear, i, j), t); } else { _nf_elem_get_fmpz_poly_lcm(fmpz_poly_mat_entry(Aclear, i, j), t, CA_NF_ELEM(ca_mat_entry(A, i, j)), Aden + i, CA_FIELD_NF(K)); } } } fmpz_clear(t); } static void get_mat_colwise(fmpz_poly_mat_t Aclear, const ca_mat_t A, const fmpz * Aden, ca_field_t K, ca_ctx_t ctx) { slong i, j; fmpz_t t; fmpz_init(t); for (i = 0; i < ca_mat_ncols(A); i++) { for (j = 0; j < ca_mat_nrows(A); j++) { if (CA_IS_QQ(ca_mat_entry(A, j, i), ctx)) { fmpz_divexact(t, Aden + i, CA_FMPQ_DENREF(ca_mat_entry(A, j, i))); fmpz_mul(t, t, CA_FMPQ_NUMREF(ca_mat_entry(A, j, i))); fmpz_poly_set_fmpz(fmpz_poly_mat_entry(Aclear, j, i), t); } else { _nf_elem_get_fmpz_poly_lcm(fmpz_poly_mat_entry(Aclear, j, i), t, CA_NF_ELEM(ca_mat_entry(A, j, i)), Aden + i, CA_FIELD_NF(K)); } } } fmpz_clear(t); } void _ca_set_nf_fmpz_poly_den(ca_t res, const fmpz_poly_t poly, const fmpz_t den, ca_field_t K, ca_ctx_t ctx) { if (poly->length == 0) { ca_zero(res, ctx); } else if (poly->length == 1) { _ca_make_fmpq(res, ctx); fmpz_gcd(CA_FMPQ_DENREF(res), poly->coeffs, den); fmpz_divexact(CA_FMPQ_NUMREF(res), poly->coeffs, CA_FMPQ_DENREF(res)); fmpz_divexact(CA_FMPQ_DENREF(res), den, CA_FMPQ_DENREF(res)); } else { fmpq_poly_t T; T->coeffs = poly->coeffs; T->length = poly->length; T->alloc = poly->alloc; T->den[0] = den[0]; _ca_make_field_element(res, K, ctx); /* work around antic bug */ if (CA_FIELD_NF(K)->flag & NF_QUADRATIC) { fmpz_set(QNF_ELEM_NUMREF(CA_NF_ELEM(res)), T->coeffs); fmpz_set(QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 1, T->coeffs + 1); if (T->length == 3) fmpz_set(QNF_ELEM_NUMREF(CA_NF_ELEM(res)) + 2, T->coeffs + 2); fmpz_set(QNF_ELEM_DENREF(CA_NF_ELEM(res)), den); /* todo: canonicalise before reduction? */ } else { nf_elem_set_fmpq_poly(CA_NF_ELEM(res), T, CA_FIELD_NF(K)); } nf_elem_reduce(CA_NF_ELEM(res), CA_FIELD_NF(K)); /* antic is currently inconsistent about canonicalising in reduce() */ if (CA_FIELD_NF(K)->flag & NF_LINEAR) nf_elem_canonicalise(CA_NF_ELEM(res), CA_FIELD_NF(K)); /* may have reduced to a rational */ ca_condense_field(res, ctx); } } void ca_mat_mul_same_nf(ca_mat_t C, const ca_mat_t A, const ca_mat_t B, ca_field_t K, ca_ctx_t ctx) { fmpz_poly_mat_t ZC, ZA, ZB; fmpz * Aden, * Bden; fmpz_t den; slong Ar, Ac, Br, Bc; slong i, j; Ar = ca_mat_nrows(A); Ac = ca_mat_ncols(A); Br = ca_mat_nrows(B); Bc = ca_mat_ncols(B); if (Ar == 0 || Ac == 0 || Bc == 0) { ca_mat_zero(C, ctx); return; } if (!CA_FIELD_IS_NF(K)) { flint_printf("ca_mat_mul_same_nf: expected a number field\n"); flint_abort(); } Aden = _fmpz_vec_init(Ar); Bden = _fmpz_vec_init(Bc); if (!get_lcm_rowwise(Aden, A, K, 1000, ctx) || !get_lcm_colwise(Bden, B, K, 1000, ctx)) { _fmpz_vec_clear(Aden, Ar); _fmpz_vec_clear(Bden, Bc); ca_mat_mul_classical(C, A, B, ctx); return; } fmpz_init(den); fmpz_poly_mat_init(ZA, Ar, Ac); fmpz_poly_mat_init(ZB, Br, Bc); fmpz_poly_mat_init(ZC, Ar, Bc); get_mat_rowwise(ZA, A, Aden, K, ctx); get_mat_colwise(ZB, B, Bden, K, ctx); fmpz_poly_mat_mul(ZC, ZA, ZB); for (i = 0; i < ca_mat_nrows(C); i++) { for (j = 0; j < ca_mat_ncols(C); j++) { fmpz_mul(den, Aden + i, Bden + j); _ca_set_nf_fmpz_poly_den(ca_mat_entry(C, i, j), fmpz_poly_mat_entry(ZC, i, j), den, K, ctx); } } fmpz_poly_mat_clear(ZA); fmpz_poly_mat_clear(ZB); fmpz_poly_mat_clear(ZC); _fmpz_vec_clear(Aden, Ar); _fmpz_vec_clear(Bden, Bc); fmpz_clear(den); } calcium-0.4.1/ca_mat/neg.c000066400000000000000000000012471407704557200153110ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_neg(ca_mat_t dest, const ca_mat_t src, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(src); i++) for (j = 0; j < ca_mat_ncols(src); j++) ca_neg(ca_mat_entry(dest, i, j), ca_mat_entry(src, i, j), ctx); } calcium-0.4.1/ca_mat/nonsingular_fflu.c000066400000000000000000000015301407704557200201060ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" truth_t ca_mat_nonsingular_fflu(slong * P, ca_mat_t LU, ca_t den, const ca_mat_t A, ca_ctx_t ctx) { if (ca_mat_is_empty(A)) { ca_one(den, ctx); return T_TRUE; } else { int success; slong rank; success = ca_mat_fflu(&rank, P, LU, den, A, 1, ctx); if (success == 0) return T_UNKNOWN; if (rank == 0) return T_FALSE; return T_TRUE; } } calcium-0.4.1/ca_mat/nonsingular_lu.c000066400000000000000000000014531407704557200175760ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" truth_t ca_mat_nonsingular_lu(slong * P, ca_mat_t LU, const ca_mat_t A, ca_ctx_t ctx) { if (ca_mat_is_empty(A)) { return T_TRUE; } else { int success; slong rank; success = ca_mat_lu(&rank, P, LU, A, 1, ctx); if (success == 0) return T_UNKNOWN; if (rank == 0) return T_FALSE; return T_TRUE; } } calcium-0.4.1/ca_mat/nonsingular_solve.c000066400000000000000000000010621407704557200203020ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" truth_t ca_mat_nonsingular_solve(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) { return ca_mat_nonsingular_solve_lu(X, A, B, ctx); } calcium-0.4.1/ca_mat/nonsingular_solve_adjugate.c000066400000000000000000000017741407704557200221600ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" truth_t ca_mat_nonsingular_solve_adjugate(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) { truth_t result; ca_t det; ca_mat_t T; ca_init(det, ctx); ca_mat_init(T, ca_mat_nrows(A), ca_mat_ncols(A), ctx); ca_mat_adjugate(T, det, A, ctx); result = ca_check_is_zero(det, ctx); if (result == T_TRUE) result = T_FALSE; else if (result == T_FALSE) result = T_TRUE; if (result == T_TRUE) { ca_mat_mul(X, T, B, ctx); ca_mat_div_ca(X, X, det, ctx); } ca_mat_clear(T, ctx); ca_clear(det, ctx); return result; } calcium-0.4.1/ca_mat/nonsingular_solve_fflu.c000066400000000000000000000017671407704557200213320ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" truth_t ca_mat_nonsingular_solve_fflu(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) { truth_t result; slong n, m, *perm; ca_mat_t LU; ca_t den; n = ca_mat_nrows(A); m = ca_mat_ncols(X); if (n == 0) return T_TRUE; perm = _perm_init(n); ca_mat_init(LU, n, n, ctx); ca_init(den, ctx); result = ca_mat_nonsingular_fflu(perm, LU, den, A, ctx); if (result == T_TRUE && m != 0) ca_mat_solve_fflu_precomp(X, perm, LU, den, B, ctx); ca_mat_clear(LU, ctx); _perm_clear(perm); ca_clear(den, ctx); return result; } calcium-0.4.1/ca_mat/nonsingular_solve_lu.c000066400000000000000000000016521407704557200210070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" truth_t ca_mat_nonsingular_solve_lu(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) { truth_t result; slong n, m, *perm; ca_mat_t LU; n = ca_mat_nrows(A); m = ca_mat_ncols(X); if (n == 0) return T_TRUE; perm = _perm_init(n); ca_mat_init(LU, n, n, ctx); result = ca_mat_nonsingular_lu(perm, LU, A, ctx); if (result == T_TRUE && m != 0) ca_mat_solve_lu_precomp(X, perm, LU, B, ctx); ca_mat_clear(LU, ctx); _perm_clear(perm); return result; } calcium-0.4.1/ca_mat/one.c000066400000000000000000000013141407704557200153140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_one(ca_mat_t mat, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(mat); i++) for (j = 0; j < ca_mat_ncols(mat); j++) if (i == j) ca_one(ca_mat_entry(mat, i, j), ctx); else ca_zero(ca_mat_entry(mat, i, j), ctx); } calcium-0.4.1/ca_mat/ones.c000066400000000000000000000012061407704557200154770ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_ones(ca_mat_t mat, ca_ctx_t ctx) { slong R, C, i, j; R = ca_mat_nrows(mat); C = ca_mat_ncols(mat); for (i = 0; i < R; i++) for (j = 0; j < C; j++) ca_one(ca_mat_entry(mat, i, j), ctx); } calcium-0.4.1/ca_mat/pascal.c000066400000000000000000000041541407704557200160030ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_pascal(ca_mat_t mat, int triangular, ca_ctx_t ctx) { slong R, C, i, j; R = ca_mat_nrows(mat); C = ca_mat_ncols(mat); if (R == 0 || C == 0) return; if (triangular == 1) { for (i = 1; i < R; i++) for (j = 0; j < i && j < C; j++) ca_zero(ca_mat_entry(mat, i, j), ctx); for (j = 0; j < C; j++) ca_one(ca_mat_entry(mat, 0, j), ctx); for (i = 1; i < R && i < C; i++) ca_one(ca_mat_entry(mat, i, i), ctx); for (i = 1; i < R; i++) for (j = i + 1; j < C; j++) ca_add(ca_mat_entry(mat, i, j), ca_mat_entry(mat, i, j - 1), ca_mat_entry(mat, i - 1, j - 1), ctx); } else if (triangular == -1) { for (i = 0; i < R; i++) for (j = i + 1; j < C; j++) ca_zero(ca_mat_entry(mat, i, j), ctx); for (i = 0; i < R; i++) ca_one(ca_mat_entry(mat, i, 0), ctx); for (i = 1; i < R && i < C; i++) ca_one(ca_mat_entry(mat, i, i), ctx); for (i = 2; i < R; i++) for (j = 1; j < i && j < C; j++) ca_add(ca_mat_entry(mat, i, j), ca_mat_entry(mat, i - 1, j - 1), ca_mat_entry(mat, i - 1, j), ctx); } else { for (j = 0; j < C; j++) ca_one(ca_mat_entry(mat, 0, j), ctx); for (i = 1; i < R; i++) ca_one(ca_mat_entry(mat, i, 0), ctx); for (i = 1; i < R; i++) for (j = 1; j < C; j++) ca_add(ca_mat_entry(mat, i, j), ca_mat_entry(mat, i, j - 1), ca_mat_entry(mat, i - 1, j), ctx); } } calcium-0.4.1/ca_mat/pow_ui_binexp.c000066400000000000000000000026771407704557200174170ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_pow_ui_binexp(ca_mat_t B, const ca_mat_t A, ulong exp, ca_ctx_t ctx) { slong d = ca_mat_nrows(A); if (exp <= 2 || d <= 1) { if (exp == 0 || d == 0) { ca_mat_one(B, ctx); } else if (d == 1) { ca_pow_ui(ca_mat_entry(B, 0, 0), ca_mat_entry(A, 0, 0), exp, ctx); } else if (exp == 1) { ca_mat_set(B, A, ctx); } else if (exp == 2) { ca_mat_sqr(B, A, ctx); } } else { ca_mat_t T, U; slong i; ca_mat_init(T, d, d, ctx); ca_mat_set(T, A, ctx); ca_mat_init(U, d, d, ctx); for (i = ((slong) FLINT_BIT_COUNT(exp)) - 2; i >= 0; i--) { ca_mat_sqr(U, T, ctx); if (exp & (WORD(1) << i)) ca_mat_mul(T, U, A, ctx); else ca_mat_swap(T, U, ctx); } ca_mat_swap(B, T, ctx); ca_mat_clear(T, ctx); ca_mat_clear(U, ctx); } } calcium-0.4.1/ca_mat/print.c000066400000000000000000000025701407704557200156740ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_print(const ca_mat_t mat, ca_ctx_t ctx) { slong r, c; slong i, j; r = ca_mat_nrows(mat); c = ca_mat_ncols(mat); flint_printf("ca_mat of size %wd x %wd:\n", r, c); for (i = 0; i < r; i++) { for (j = 0; j < c; j++) { flint_printf(" "); ca_print(ca_mat_entry(mat, i, j), ctx); flint_printf("\n"); } } flint_printf("\n"); } void ca_mat_printn(const ca_mat_t mat, slong digits, ca_ctx_t ctx) { slong r, c; slong i, j; r = ca_mat_nrows(mat); c = ca_mat_ncols(mat); flint_printf("["); for (i = 0; i < r; i++) { flint_printf("["); for (j = 0; j < c; j++) { ca_printn(ca_mat_entry(mat, i, j), digits, ctx); if (j < c - 1) flint_printf(", "); } if (i < r - 1) flint_printf("],\n"); else flint_printf("]"); } flint_printf("]\n"); } calcium-0.4.1/ca_mat/randops.c000066400000000000000000000031501407704557200162010ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_randops(ca_mat_t mat, flint_rand_t state, slong count, ca_ctx_t ctx) { slong c, i, j, k; slong m = mat->r; slong n = mat->c; if (mat->r == 0 || mat->c == 0) return; for (c = 0; c < count; c++) { if (n_randint(state, 2)) { if ((i = n_randint(state, m)) == (j = n_randint(state, m))) continue; if (n_randint(state, 2)) for (k = 0; k < n; k++) ca_add(ca_mat_entry(mat, j, k), ca_mat_entry(mat, j, k), ca_mat_entry(mat, i, k), ctx); else for (k = 0; k < n; k++) ca_sub(ca_mat_entry(mat, j, k), ca_mat_entry(mat, j, k), ca_mat_entry(mat, i, k), ctx); } else { if ((i = n_randint(state, n)) == (j = n_randint(state, n))) continue; if (n_randint(state, 2)) for (k = 0; k < m; k++) ca_add(ca_mat_entry(mat, k, j), ca_mat_entry(mat, k, j), ca_mat_entry(mat, k, i), ctx); else for (k = 0; k < m; k++) ca_sub(ca_mat_entry(mat, k, j), ca_mat_entry(mat, k, j), ca_mat_entry(mat, k, i), ctx); } } } calcium-0.4.1/ca_mat/randtest.c000066400000000000000000000024461407704557200163660ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_randtest(ca_mat_t mat, flint_rand_t state, slong length, slong bits, ca_ctx_t ctx) { slong i, j, density; density = n_randint(state, 100); for (i = 0; i < ca_mat_nrows(mat); i++) for (j = 0; j < ca_mat_ncols(mat); j++) if (n_randint(state, 100) < density) ca_randtest(ca_mat_entry(mat, i, j), state, length, bits, ctx); else ca_zero(ca_mat_entry(mat, i, j), ctx); } void ca_mat_randtest_rational(ca_mat_t mat, flint_rand_t state, slong bits, ca_ctx_t ctx) { slong i, j, density; density = n_randint(state, 100); for (i = 0; i < ca_mat_nrows(mat); i++) for (j = 0; j < ca_mat_ncols(mat); j++) if (n_randint(state, 100) < density) ca_randtest_rational(ca_mat_entry(mat, i, j), state, bits, ctx); else ca_zero(ca_mat_entry(mat, i, j), ctx); } calcium-0.4.1/ca_mat/rank.c000066400000000000000000000015501407704557200154700ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" /* todo: different algorithms... */ int ca_mat_rank(slong * rank, const ca_mat_t A, ca_ctx_t ctx) { slong n, m; slong * P; int success; ca_mat_t T; n = ca_mat_nrows(A); m = ca_mat_ncols(A); if (n == 0 || m == 0) { *rank = 0; return 1; } ca_mat_init(T, n, m, ctx); P = _perm_init(n); success = ca_mat_lu(rank, P, T, A, 0, ctx); ca_mat_clear(T, ctx); _perm_clear(P); return success; } calcium-0.4.1/ca_mat/right_kernel.c000066400000000000000000000045571407704557200172240ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_right_kernel(ca_mat_t X, const ca_mat_t A, ca_ctx_t ctx) { slong i, j, k, m, n, rank, nullity; slong *p; slong *pivots; slong *nonpivots; ca_mat_t tmp; int success; m = ca_mat_nrows(A); n = ca_mat_ncols(A); p = flint_malloc(sizeof(slong) * FLINT_MAX(m, n)); ca_mat_init(tmp, m, n, ctx); success = ca_mat_rref(&rank, tmp, A, ctx); nullity = n - rank; if (!success) goto cleanup; ca_mat_clear(X, ctx); ca_mat_init(X, n, nullity, ctx); success = 1; if (rank == 0) { for (i = 0; i < nullity; i++) ca_one(ca_mat_entry(X, i, i), ctx); } else if (nullity) { pivots = p; /* length = rank */ nonpivots = p + rank; /* length = nullity */ for (i = j = k = 0; i < rank; i++) { while (1) { /* Todo: this should not be T_UNKNOWN. Should we save the pivot data in the lu algorithm? */ truth_t is_zero = ca_check_is_zero(ca_mat_entry(tmp, i, j), ctx); if (is_zero == T_FALSE) { break; } else if (is_zero == T_TRUE) { nonpivots[k] = j; k++; j++; } else { success = 0; goto cleanup; } } pivots[i] = j; j++; } while (k < n - rank) { nonpivots[k] = j; k++; j++; } for (i = 0; i < nullity; i++) { for (j = 0; j < rank; j++) ca_neg(ca_mat_entry(X, pivots[j], i), ca_mat_entry(tmp, j, nonpivots[i]), ctx); ca_one(ca_mat_entry(X, nonpivots[i], i), ctx); } } cleanup: flint_free(p); ca_mat_clear(tmp, ctx); return success; } calcium-0.4.1/ca_mat/rref.c000066400000000000000000000010231407704557200154660ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_rref(slong * rank, ca_mat_t R, const ca_mat_t A, ca_ctx_t ctx) { return ca_mat_rref_lu(rank, R, A, ctx); } calcium-0.4.1/ca_mat/rref_fflu.c000066400000000000000000000067301407704557200165140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_rref_fflu(slong * res_rank, ca_mat_t R, const ca_mat_t A, ca_ctx_t ctx) { slong i, j, k, m, n, rank; slong *pivots, *nonpivots; ca_t den; int success; ca_init(den, ctx); success = ca_mat_fflu(&rank, NULL, R, den, A, 0, ctx); if (!success) { ca_clear(den, ctx); return 0; } m = ca_mat_nrows(R); n = ca_mat_ncols(R); /* clear bottom */ for (i = rank; i < m; i++) for (j = 0; j < n; j++) ca_zero(ca_mat_entry(R, i, j), ctx); /* Convert row echelon form to reduced row echelon form */ if (rank > 1) { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); pivots = flint_malloc(sizeof(slong) * n); nonpivots = pivots + rank; for (i = j = k = 0; i < rank; i++) { while (1) { /* Todo: this should not be T_UNKNOWN. Should we save the pivot data in the lu algorithm? */ truth_t is_zero = ca_check_is_zero(ca_mat_entry(R, i, j), ctx); if (is_zero == T_FALSE) { break; } else if (is_zero == T_TRUE) { nonpivots[k] = j; k++; j++; } else { success = 0; goto cleanup1; } } pivots[i] = j; j++; } while (k < n - rank) { nonpivots[k] = j; k++; j++; } for (k = 0; k < n - rank; k++) { for (i = rank - 2; i >= 0; i--) { ca_mul(t, den, ca_mat_entry(R, i, nonpivots[k]), ctx); for (j = i + 1; j < rank; j++) { ca_mul(u, ca_mat_entry(R, i, pivots[j]), ca_mat_entry(R, j, nonpivots[k]), ctx); ca_sub(t, t, u, ctx); } ca_div(ca_mat_entry(R, i, nonpivots[k]), t, ca_mat_entry(R, i, pivots[i]), ctx); } } /* clear pivot columns */ for (i = 0; i < rank; i++) { for (j = 0; j < rank; j++) { if (i == j) ca_one(ca_mat_entry(R, j, pivots[i]), ctx); else ca_zero(ca_mat_entry(R, j, pivots[i]), ctx); } } /* divide out denominator */ if (ca_check_is_one(den, ctx) != T_TRUE) for (i = 0; i < rank; i++) for (j = 0; j < n - rank; j++) ca_div(ca_mat_entry(R, i, nonpivots[j]), ca_mat_entry(R, i, nonpivots[j]), den, ctx); cleanup1: flint_free(pivots); ca_clear(t, ctx); ca_clear(u, ctx); } else if (rank == 1 && ca_check_is_one(den, ctx) != T_TRUE) { for (i = 0; i < n; i++) ca_div(ca_mat_entry(R, 0, i), ca_mat_entry(R, 0, i), den, ctx); } ca_clear(den, ctx); *res_rank = rank; return success; } calcium-0.4.1/ca_mat/rref_lu.c000066400000000000000000000064231407704557200161770ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int ca_mat_rref_lu(slong * res_rank, ca_mat_t R, const ca_mat_t A, ca_ctx_t ctx) { slong i, j, k, n, rank; slong *pivots; slong *nonpivots; slong *P; ca_mat_t U, V; int success; if (ca_mat_check_is_zero(A, ctx) == T_TRUE) { *res_rank = 0; return 1; } /* Todo: fast path for nrows == 1 */ n = A->c; P = _perm_init(ca_mat_nrows(A)); success = ca_mat_lu(&rank, P, R, A, 0, ctx); _perm_clear(P); if (!success) return 0; if (rank == 0) { *res_rank = 0; return 1; } /* Clear L */ for (i = 0; i < A->r; i++) for (j = 0; j < FLINT_MIN(i, rank); j++) ca_zero(ca_mat_entry(R, i, j), ctx); /* We now reorder U to proper upper triangular form U | V with U full-rank triangular, set V = U^(-1) V, and then put the column back in the original order. An improvement for some matrices would be to compress V by discarding columns containing nothing but zeros. */ ca_mat_init(U, rank, rank, ctx); ca_mat_init(V, rank, n - rank, ctx); pivots = flint_malloc(sizeof(slong) * rank); nonpivots = flint_malloc(sizeof(slong) * (n - rank)); for (i = j = k = 0; i < rank; i++) { while (1) { /* Todo: this should not be T_UNKNOWN. Should we save the pivot data in the lu algorithm? */ truth_t is_zero = ca_check_is_zero(ca_mat_entry(R, i, j), ctx); if (is_zero == T_FALSE) { break; } else if (is_zero == T_TRUE) { nonpivots[k] = j; k++; j++; } else { success = 0; goto cleanup1; } } pivots[i] = j; j++; } while (k < n - rank) { nonpivots[k] = j; k++; j++; } for (i = 0; i < rank; i++) for (j = 0; j <= i; j++) ca_set(ca_mat_entry(U, j, i), ca_mat_entry(R, j, pivots[i]), ctx); for (i = 0; i < n - rank; i++) for (j = 0; j < rank; j++) ca_set(ca_mat_entry(V, j, i), ca_mat_entry(R, j, nonpivots[i]), ctx); ca_mat_solve_triu(V, U, V, 0, ctx); /* Clear pivot columns */ for (i = 0; i < rank; i++) { for (j = 0; j <= i; j++) { if (i == j) ca_one(ca_mat_entry(R, j, pivots[i]), ctx); else ca_zero(ca_mat_entry(R, j, pivots[i]), ctx); } } /* Write back the actual content */ for (i = 0; i < n - rank; i++) for (j = 0; j < rank; j++) ca_set(ca_mat_entry(R, j, nonpivots[i]), ca_mat_entry(V, j, i), ctx); cleanup1: ca_mat_clear(U, ctx); ca_mat_clear(V, ctx); flint_free(pivots); flint_free(nonpivots); *res_rank = rank; return 1; } calcium-0.4.1/ca_mat/set.c000066400000000000000000000013621407704557200153310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_set(ca_mat_t dest, const ca_mat_t src, ca_ctx_t ctx) { slong i, j; if (dest != src && ca_mat_ncols(src) != 0) { for (i = 0; i < ca_mat_nrows(src); i++) for (j = 0; j < ca_mat_ncols(src); j++) ca_set(ca_mat_entry(dest, i, j), ca_mat_entry(src, i, j), ctx); } } calcium-0.4.1/ca_mat/set_ca.c000066400000000000000000000013661407704557200160000ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_set_ca(ca_mat_t y, const ca_t x, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(y); i++) { for (j = 0; j < ca_mat_ncols(y); j++) { if (i == j) ca_set(ca_mat_entry(y, i, j), x, ctx); else ca_zero(ca_mat_entry(y, i, j), ctx); } } } calcium-0.4.1/ca_mat/set_fmpq_mat.c000066400000000000000000000013701407704557200172140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_set_fmpq_mat(ca_mat_t dest, const fmpq_mat_t src, ca_ctx_t ctx) { slong i, j; if (ca_mat_ncols(dest) != 0) { for (i = 0; i < ca_mat_nrows(dest); i++) for (j = 0; j < ca_mat_ncols(dest); j++) ca_set_fmpq(ca_mat_entry(dest, i, j), fmpq_mat_entry(src, i, j), ctx); } } calcium-0.4.1/ca_mat/set_fmpz_mat.c000066400000000000000000000013701407704557200172250ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_set_fmpz_mat(ca_mat_t dest, const fmpz_mat_t src, ca_ctx_t ctx) { slong i, j; if (ca_mat_ncols(dest) != 0) { for (i = 0; i < ca_mat_nrows(dest); i++) for (j = 0; j < ca_mat_ncols(dest); j++) ca_set_fmpz(ca_mat_entry(dest, i, j), fmpz_mat_entry(src, i, j), ctx); } } calcium-0.4.1/ca_mat/solve_fflu_precomp.c000066400000000000000000000045411407704557200204310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_solve_fflu_precomp(ca_mat_t X, const slong * perm, const ca_mat_t A, const ca_t den, const ca_mat_t B, ca_ctx_t ctx) { ca_t t; slong i, j, k, c, n, m; n = ca_mat_nrows(X); m = ca_mat_ncols(X); if (X == B) { ca_ptr tmp = flint_malloc(sizeof(ca_struct) * n); for (c = 0; c < m; c++) { for (i = 0; i < n; i++) tmp[i] = B->rows[perm[i]][c]; for (i = 0; i < n; i++) X->rows[i][c] = tmp[i]; } flint_free(tmp); } else { for (c = 0; c < m; c++) { for (i = 0; i < n; i++) { ca_set(ca_mat_entry(X, i, c), ca_mat_entry(B, perm[i], c), ctx); } } } ca_init(t, ctx); for (k = 0; k < m; k++) { /* Fraction-free forward substitution */ for (i = 0; i < n - 1; i++) { for (j = i + 1; j < n; j++) { ca_mul(ca_mat_entry(X, j, k), ca_mat_entry(X, j, k), ca_mat_entry(A, i, i), ctx); ca_mul(t, ca_mat_entry(A, j, i), ca_mat_entry(X, i, k), ctx); ca_sub(ca_mat_entry(X, j, k), ca_mat_entry(X, j, k), t, ctx); if (i > 0) ca_div(ca_mat_entry(X, j, k), ca_mat_entry(X, j, k), ca_mat_entry(A, i-1, i-1), ctx); } } /* Fraction-free back substitution */ for (i = n - 2; i >= 0; i--) { ca_mul(ca_mat_entry(X, i, k), ca_mat_entry(X, i, k), ca_mat_entry(A, n-1, n-1), ctx); for (j = i + 1; j < n; j++) { ca_mul(t, ca_mat_entry(X, j, k), ca_mat_entry(A, i, j), ctx); ca_sub(ca_mat_entry(X, i, k), ca_mat_entry(X, i, k), t, ctx); } ca_div(ca_mat_entry(X, i, k), ca_mat_entry(X, i, k), ca_mat_entry(A, i, i), ctx); } } ca_mat_div_ca(X, X, den, ctx); ca_clear(t, ctx); } calcium-0.4.1/ca_mat/solve_lu_precomp.c000066400000000000000000000024001407704557200201050ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_solve_lu_precomp(ca_mat_t X, const slong * perm, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) { slong i, c, n, m; n = ca_mat_nrows(X); m = ca_mat_ncols(X); if (X == B) { ca_ptr tmp = flint_malloc(sizeof(ca_struct) * n); for (c = 0; c < m; c++) { for (i = 0; i < n; i++) tmp[i] = B->rows[perm[i]][c]; for (i = 0; i < n; i++) X->rows[i][c] = tmp[i]; } flint_free(tmp); } else { for (c = 0; c < m; c++) { for (i = 0; i < n; i++) { ca_set(ca_mat_entry(X, i, c), ca_mat_entry(B, perm[i], c), ctx); } } } /* todo: inline for small n? */ ca_mat_solve_tril(X, A, X, 1, ctx); ca_mat_solve_triu(X, A, X, 0, ctx); } calcium-0.4.1/ca_mat/solve_tril.c000066400000000000000000000053521407704557200167230ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_solve_tril_classical(ca_mat_t X, const ca_mat_t L, const ca_mat_t B, int unit, ca_ctx_t ctx) { slong i, j, n, m; ca_ptr tmp; ca_t s; n = L->r; m = B->c; ca_init(s, ctx); tmp = flint_malloc(sizeof(ca_struct) * n); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) tmp[j] = *ca_mat_entry(X, j, i); for (j = 0; j < n; j++) { ca_dot(s, ca_mat_entry(B, j, i), 1, L->rows[j], 1, tmp, 1, j, ctx); if (!unit) ca_div(tmp + j, s, ca_mat_entry(L, j, j), ctx); else ca_swap(tmp + j, s, ctx); } for (j = 0; j < n; j++) *ca_mat_entry(X, j, i) = tmp[j]; } flint_free(tmp); ca_clear(s, ctx); } void ca_mat_solve_tril_recursive(ca_mat_t X, const ca_mat_t L, const ca_mat_t B, int unit, ca_ctx_t ctx) { ca_mat_t LA, LC, LD, XX, XY, BX, BY, T; slong r, n, m; n = L->r; m = B->c; r = n / 2; if (n == 0 || m == 0) return; /* Denoting inv(M) by M^, we have: [A 0]^ [X] == [A^ 0 ] [X] == [A^ X] [C D] [Y] == [-D^ C A^ D^] [Y] == [D^ (Y - C A^ X)] */ ca_mat_window_init(LA, L, 0, 0, r, r, ctx); ca_mat_window_init(LC, L, r, 0, n, r, ctx); ca_mat_window_init(LD, L, r, r, n, n, ctx); ca_mat_window_init(BX, B, 0, 0, r, m, ctx); ca_mat_window_init(BY, B, r, 0, n, m, ctx); ca_mat_window_init(XX, X, 0, 0, r, m, ctx); ca_mat_window_init(XY, X, r, 0, n, m, ctx); ca_mat_solve_tril(XX, LA, BX, unit, ctx); /* ca_mat_submul(XY, BY, LC, XX); */ ca_mat_init(T, LC->r, BX->c, ctx); ca_mat_mul(T, LC, XX, ctx); ca_mat_sub(XY, BY, T, ctx); ca_mat_clear(T, ctx); ca_mat_solve_tril(XY, LD, XY, unit, ctx); ca_mat_window_clear(LA, ctx); ca_mat_window_clear(LC, ctx); ca_mat_window_clear(LD, ctx); ca_mat_window_clear(BX, ctx); ca_mat_window_clear(BY, ctx); ca_mat_window_clear(XX, ctx); ca_mat_window_clear(XY, ctx); } void ca_mat_solve_tril(ca_mat_t X, const ca_mat_t L, const ca_mat_t B, int unit, ca_ctx_t ctx) { /* todo: tune thresholds */ if (B->r < 10 || B->c < 10) ca_mat_solve_tril_classical(X, L, B, unit, ctx); else ca_mat_solve_tril_recursive(X, L, B, unit, ctx); } calcium-0.4.1/ca_mat/solve_triu.c000066400000000000000000000053321407704557200167320ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_solve_triu_classical(ca_mat_t X, const ca_mat_t U, const ca_mat_t B, int unit, ca_ctx_t ctx) { slong i, j, n, m; ca_ptr tmp; ca_t s; n = U->r; m = B->c; ca_init(s, ctx); tmp = flint_malloc(sizeof(ca_struct) * n); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) tmp[j] = *ca_mat_entry(X, j, i); for (j = n - 1; j >= 0; j--) { ca_dot(s, ca_mat_entry(B, j, i), 1, U->rows[j] + j + 1, 1, tmp + j + 1, 1, n - j - 1, ctx); if (!unit) ca_div(tmp + j, s, ca_mat_entry(U, j, j), ctx); else ca_swap(tmp + j, s, ctx); } for (j = 0; j < n; j++) *ca_mat_entry(X, j, i) = tmp[j]; } flint_free(tmp); ca_clear(s, ctx); } void ca_mat_solve_triu_recursive(ca_mat_t X, const ca_mat_t U, const ca_mat_t B, int unit, ca_ctx_t ctx) { ca_mat_t UA, UB, UD, XX, XY, BX, BY, T; slong r, n, m; n = U->r; m = B->c; r = n / 2; if (n == 0 || m == 0) return; /* Denoting inv(M) by M^, we have: [A B]^ [X] == [A^ (X - B D^ Y)] [0 D] [Y] == [ D^ Y ] */ ca_mat_window_init(UA, U, 0, 0, r, r, ctx); ca_mat_window_init(UB, U, 0, r, r, n, ctx); ca_mat_window_init(UD, U, r, r, n, n, ctx); ca_mat_window_init(BX, B, 0, 0, r, m, ctx); ca_mat_window_init(BY, B, r, 0, n, m, ctx); ca_mat_window_init(XX, X, 0, 0, r, m, ctx); ca_mat_window_init(XY, X, r, 0, n, m, ctx); ca_mat_solve_triu(XY, UD, BY, unit, ctx); /* ca_mat_submul(XX, BX, UB, XY); */ ca_mat_init(T, UB->r, XY->c, ctx); ca_mat_mul(T, UB, XY, ctx); ca_mat_sub(XX, BX, T, ctx); ca_mat_clear(T, ctx); ca_mat_solve_triu(XX, UA, XX, unit, ctx); ca_mat_window_clear(UA, ctx); ca_mat_window_clear(UB, ctx); ca_mat_window_clear(UD, ctx); ca_mat_window_clear(BX, ctx); ca_mat_window_clear(BY, ctx); ca_mat_window_clear(XX, ctx); ca_mat_window_clear(XY, ctx); } void ca_mat_solve_triu(ca_mat_t X, const ca_mat_t U, const ca_mat_t B, int unit, ca_ctx_t ctx) { /* todo: tune thresholds */ if (B->r < 10 || B->c < 10) ca_mat_solve_triu_classical(X, U, B, unit, ctx); else ca_mat_solve_triu_recursive(X, U, B, unit, ctx); } calcium-0.4.1/ca_mat/stirling.c000066400000000000000000000053151407704557200163730ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" static void _stirling_number_1u_vec_next(ca_ptr row, ca_srcptr prev, slong n, slong klen, ca_ctx_t ctx) { slong k; if (klen > n) ca_one(row + n, ctx); if (n != 0 && klen != 0) ca_zero(row, ctx); for (k = FLINT_MIN(n, klen) - 1; k >= 1; k--) { ca_mul_ui(row + k, prev + k, n - 1, ctx); ca_add(row + k, prev + k - 1, row + k, ctx); } for (k = n + 1; k < klen; k++) ca_zero(row + k, ctx); } static void _stirling_number_1_vec_next(ca_ptr row, ca_srcptr prev, slong n, slong klen, ca_ctx_t ctx) { slong k; if (klen > n) ca_one(row + n, ctx); if (n != 0 && klen != 0) ca_zero(row, ctx); for (k = FLINT_MIN(n, klen) - 1; k >= 1; k--) { ca_mul_ui(row + k, prev + k, n - 1, ctx); ca_sub(row + k, prev + k - 1, row + k, ctx); } for (k = n + 1; k < klen; k++) ca_zero(row + k, ctx); } static void _stirling_number_2_vec_next(ca_ptr row, ca_srcptr prev, slong n, slong klen, ca_ctx_t ctx) { slong k; if (klen > n) ca_one(row + n, ctx); if (n != 0 && klen != 0) ca_zero(row, ctx); for (k = FLINT_MIN(n, klen) - 1; k >= 1; k--) { ca_mul_ui(row + k, prev + k, k, ctx); ca_add(row + k, prev + k - 1, row + k, ctx); } for (k = n + 1; k < klen; k++) ca_zero(row + k, ctx); } static void _stirling_matrix_1u(ca_mat_t mat, ca_ctx_t ctx) { slong n; if (ca_mat_is_empty(mat)) return; for (n = 0; n < mat->r; n++) _stirling_number_1u_vec_next(mat->rows[n], mat->rows[n - (n != 0)], n, mat->c, ctx); } static void _stirling_matrix_1(ca_mat_t mat, ca_ctx_t ctx) { slong n; if (ca_mat_is_empty(mat)) return; for (n = 0; n < mat->r; n++) _stirling_number_1_vec_next(mat->rows[n], mat->rows[n - (n != 0)], n, mat->c, ctx); } static void _stirling_matrix_2(ca_mat_t mat, ca_ctx_t ctx) { slong n; if (ca_mat_is_empty(mat)) return; for (n = 0; n < mat->r; n++) _stirling_number_2_vec_next(mat->rows[n], mat->rows[n - (n != 0)], n, mat->c, ctx); } void ca_mat_stirling(ca_mat_t mat, int kind, ca_ctx_t ctx) { if (kind == 0) _stirling_matrix_1u(mat, ctx); else if (kind == 1) _stirling_matrix_1(mat, ctx); else _stirling_matrix_2(mat, ctx); } calcium-0.4.1/ca_mat/sub.c000066400000000000000000000013601407704557200153250ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_sub(ca_mat_t res, const ca_mat_t mat1, const ca_mat_t mat2, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(mat1); i++) for (j = 0; j < ca_mat_ncols(mat1); j++) ca_sub(ca_mat_entry(res, i, j), ca_mat_entry(mat1, i, j), ca_mat_entry(mat2, i, j), ctx); } calcium-0.4.1/ca_mat/sub_ca.c000066400000000000000000000020641407704557200157720ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_sub_ca(ca_mat_t y, const ca_mat_t a, const ca_t x, ca_ctx_t ctx) { slong i, j, n; if (a == y) { n = FLINT_MIN(ca_mat_nrows(a), ca_mat_ncols(a)); for (i = 0; i < n; i++) ca_sub(ca_mat_entry(y, i, i), ca_mat_entry(y, i, i), x, ctx); } else { for (i = 0; i < ca_mat_nrows(a); i++) { for (j = 0; j < ca_mat_ncols(a); j++) { if (i == j) ca_sub(ca_mat_entry(y, i, j), ca_mat_entry(a, i, j), x, ctx); else ca_set(ca_mat_entry(y, i, j), ca_mat_entry(a, i, j), ctx); } } } } calcium-0.4.1/ca_mat/submul_ca.c000066400000000000000000000014571407704557200165150ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_submul_ca(ca_mat_t y, const ca_mat_t a, const ca_t x, ca_ctx_t ctx) { slong i, j; ca_t t; ca_init(t, ctx); for (i = 0; i < ca_mat_nrows(a); i++) { for (j = 0; j < ca_mat_ncols(a); j++) { ca_mul(t, ca_mat_entry(a, i, j), x, ctx); ca_sub(ca_mat_entry(y, i, j), ca_mat_entry(y, i, j), t, ctx); } } ca_clear(t, ctx); } calcium-0.4.1/ca_mat/test/000077500000000000000000000000001407704557200153475ustar00rootroot00000000000000calcium-0.4.1/ca_mat/test/t-adjugate.c000066400000000000000000000035461407704557200175500ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("adjugate..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 300 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B, C; ca_t d, e; slong n; ca_ctx_init(ctx); n = n_randint(state, 5); ca_mat_init(A, n, n, ctx); ca_mat_init(B, n, n, ctx); ca_mat_init(C, n, n, ctx); ca_init(d, ctx); ca_init(e, ctx); ca_mat_randtest(A, state, 1, 5, ctx); ca_mat_adjugate_cofactor(B, d, A, ctx); ca_mat_adjugate_charpoly(C, e, A, ctx); if (ca_mat_check_equal(B, C, ctx) == T_FALSE || ca_check_equal(d, e, ctx) == T_FALSE) { flint_printf("FAIL\n"); flint_printf("A = "), ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "), ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("C = "), ca_mat_print(C, ctx); flint_printf("\n"); flint_printf("d = "), ca_print(d, ctx); flint_printf("\n"); flint_printf("e = "), ca_print(e, ctx); flint_printf("\n"); flint_abort(); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(C, ctx); ca_clear(d, ctx); ca_clear(e, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-ca_poly_evaluate.c000066400000000000000000000050041407704557200212670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("ca_poly_evaluate...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 300 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, fA, gA, fgA, fAgA; ca_poly_t f, g, fg; slong n; n = n_randint(state, 3); ca_ctx_init(ctx); ca_mat_init(A, n, n, ctx); ca_mat_init(fA, n, n, ctx); ca_mat_init(gA, n, n, ctx); ca_mat_init(fgA, n, n, ctx); ca_mat_init(fAgA, n, n, ctx); ca_poly_init(f, ctx); ca_poly_init(g, ctx); ca_poly_init(fg, ctx); ca_mat_randtest(A, state, 1, 10, ctx); ca_mat_randtest(fA, state, 2, 10, ctx); ca_mat_randtest(gA, state, 2, 10, ctx); ca_mat_randtest(fgA, state, 2, 10, ctx); ca_poly_randtest_rational(f, state, 10, 5, ctx); ca_poly_randtest_rational(g, state, 10, 5, ctx); ca_poly_add(fg, f, g, ctx); ca_mat_ca_poly_evaluate(fA, f, A, ctx); ca_mat_set(gA, A, ctx); ca_mat_ca_poly_evaluate(gA, g, gA, ctx); ca_mat_ca_poly_evaluate(fgA, fg, A, ctx); ca_mat_add(fAgA, fA, gA, ctx); if (ca_mat_check_equal(fgA, fAgA, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("f = "); ca_poly_print(f, ctx); flint_printf("\n"); flint_printf("g = "); ca_poly_print(g, ctx); flint_printf("\n"); flint_printf("fgA = "); ca_mat_print(fgA, ctx); flint_printf("\n"); flint_printf("fAgA = "); ca_mat_print(fAgA, ctx); flint_printf("\n"); flint_abort(); } ca_mat_clear(A, ctx); ca_mat_clear(fA, ctx); ca_mat_clear(gA, ctx); ca_mat_clear(fgA, ctx); ca_mat_clear(fAgA, ctx); ca_poly_clear(f, ctx); ca_poly_clear(g, ctx); ca_poly_clear(fg, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-charpoly.c000066400000000000000000000031251407704557200175760ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("charpoly..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 300 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, fA; ca_poly_t f; slong n; ca_ctx_init(ctx); n = n_randint(state, 5); ca_mat_init(A, n, n, ctx); ca_mat_init(fA, n, n, ctx); ca_poly_init(f, ctx); ca_mat_randtest(A, state, 1, 5, ctx); ca_mat_charpoly(f, A, ctx); ca_mat_ca_poly_evaluate(fA, f, A, ctx); if (f->length != (n + 1) || ca_mat_check_is_zero(fA, ctx) != T_TRUE) { flint_printf("FAIL\n"); flint_printf("A = "), ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("f = "), ca_poly_print(f, ctx); flint_printf("\n"); flint_printf("fA = "); ca_mat_print(fA, ctx); flint_printf("\n"); flint_abort(); } ca_mat_clear(A, ctx); ca_mat_clear(fA, ctx); ca_poly_clear(f, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-charpoly_danilevsky.c000066400000000000000000000032561407704557200220340ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("charpoly_danilevsky..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, fA; ca_poly_t f; slong n; ca_ctx_init(ctx); n = n_randint(state, 10); ca_mat_init(A, n, n, ctx); ca_mat_init(fA, n, n, ctx); ca_poly_init(f, ctx); ca_mat_randtest_rational(A, state, 5, ctx); if (ca_mat_charpoly_danilevsky(f, A, ctx)) { ca_mat_ca_poly_evaluate(fA, f, A, ctx); if (f->length != (n + 1) || ca_mat_check_is_zero(fA, ctx) != T_TRUE) { flint_printf("FAIL\n"); flint_printf("A = "), ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("f = "), ca_poly_print(f, ctx); flint_printf("\n"); flint_printf("fA = "); ca_mat_print(fA, ctx); flint_printf("\n"); flint_abort(); } } ca_mat_clear(A, ctx); ca_mat_clear(fA, ctx); ca_poly_clear(f, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-companion.c000066400000000000000000000034351407704557200177440ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("companion..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A; ca_poly_t f, g; slong n; ca_ctx_init(ctx); ca_poly_init(f, ctx); ca_poly_init(g, ctx); do { ca_poly_randtest(f, state, 1 + n_randint(state, 4), 2, 5, ctx); } while (f->length < 1); n = f->length - 1; ca_mat_init(A, n, n, ctx); ca_mat_randtest_rational(A, state, 100, ctx); if (ca_mat_companion(A, f, ctx)) { ca_mat_charpoly(g, A, ctx); ca_poly_mul_ca(g, g, f->coeffs + n, ctx); if (ca_poly_check_equal(g, f, ctx) == T_FALSE) { flint_printf("FAIL\n"); flint_printf("A = "), ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("f = "), ca_poly_print(f, ctx); flint_printf("\n"); flint_printf("g = "); ca_poly_print(g, ctx); flint_printf("\n"); flint_abort(); } } ca_mat_clear(A, ctx); ca_poly_clear(f, ctx); ca_poly_clear(g, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-det.c000066400000000000000000000112441407704557200165320ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("det...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A; ca_t detA, detB; slong n; ca_ctx_init(ctx); n = n_randint(state, 6); ca_mat_init(A, n, n, ctx); ca_init(detA, ctx); ca_init(detB, ctx); ca_mat_randtest(A, state, 3, 5, ctx); switch (n_randint(state, 5)) { case 0: ca_mat_det_berkowitz(detA, A, ctx); break; case 1: ca_mat_det_lu(detA, A, ctx); break; case 2: ca_mat_det_bareiss(detA, A, ctx); break; default: ca_mat_det(detA, A, ctx); break; } switch (n_randint(state, 5)) { case 0: ca_mat_det_berkowitz(detB, A, ctx); break; case 1: ca_mat_det_lu(detB, A, ctx); break; case 2: ca_mat_det_bareiss(detB, A, ctx); break; default: ca_mat_det(detB, A, ctx); break; } if (ca_check_equal(detA, detB, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("detA = "); ca_print(detA, ctx); flint_printf("\n"); flint_printf("detB = "); ca_print(detB, ctx); flint_printf("\n"); flint_abort(); } ca_mat_clear(A, ctx); ca_clear(detA, ctx); ca_clear(detB, ctx); ca_ctx_clear(ctx); } for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B, AB; ca_t detA, detB, detAB, detAdetB; slong n; ca_ctx_init(ctx); n = n_randint(state, 5); ca_mat_init(A, n, n, ctx); ca_mat_init(B, n, n, ctx); ca_mat_init(AB, n, n, ctx); ca_init(detA, ctx); ca_init(detB, ctx); ca_init(detAB, ctx); ca_init(detAdetB, ctx); if (n_randint(state, 2)) ca_mat_randtest_rational(A, state, 100, ctx); else ca_mat_randtest(A, state, 3, 5, ctx); if (n_randint(state, 2)) ca_mat_randtest_rational(B, state, 10, ctx); else ca_mat_randtest(B, state, 3, 5, ctx); ca_mat_mul(AB, A, B, ctx); switch (n_randint(state, 5)) { case 0: ca_mat_det_berkowitz(detA, A, ctx); break; case 1: ca_mat_det_lu(detA, A, ctx); break; case 2: ca_mat_det_bareiss(detA, A, ctx); break; default: ca_mat_det(detA, A, ctx); break; } switch (n_randint(state, 5)) { case 0: ca_mat_det_berkowitz(detB, B, ctx); break; case 1: ca_mat_det_lu(detB, B, ctx); break; case 2: ca_mat_det_bareiss(detB, B, ctx); break; default: ca_mat_det(detB, B, ctx); break; } switch (n_randint(state, 5)) { case 0: ca_mat_det_berkowitz(detAB, AB, ctx); break; case 1: ca_mat_det_lu(detAB, AB, ctx); break; case 2: ca_mat_det_bareiss(detAB, AB, ctx); break; default: ca_mat_det(detAB, AB, ctx); break; } ca_mul(detAdetB, detA, detB, ctx); if (ca_check_equal(detAB, detAdetB, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("AB = "); ca_mat_print(AB, ctx); flint_printf("\n"); flint_printf("detA = "); ca_print(detA, ctx); flint_printf("\n"); flint_printf("detB = "); ca_print(detB, ctx); flint_printf("\n"); flint_printf("detAB = "); ca_print(detAB, ctx); flint_printf("\n"); flint_printf("detAdetB = "); ca_print(detAdetB, ctx); flint_printf("\n"); flint_abort(); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(AB, ctx); ca_clear(detA, ctx); ca_clear(detB, ctx); ca_clear(detAB, ctx); ca_clear(detAdetB, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-dft.c000066400000000000000000000040671407704557200165400ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("dft...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1; iter++) { ca_ctx_t ctx; ca_mat_t A, B, C; slong n; ca_ctx_init(ctx); for (n = 0; n <= 16; n++) { ca_mat_init(A, n, n, ctx); ca_mat_init(B, n, n, ctx); ca_mat_init(C, n, n, ctx); ca_mat_dft(A, 0, ctx); ca_mat_dft(B, 1, ctx); ca_mat_mul(C, A, B, ctx); if (ca_mat_check_is_one(C, ctx) != T_TRUE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("C = "); ca_mat_print(C, ctx); flint_printf("\n"); flint_abort(); } ca_mat_dft(A, 2, ctx); ca_mat_dft(B, 3, ctx); ca_mat_mul(C, A, B, ctx); if (ca_mat_check_is_one(C, ctx) != T_TRUE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("C = "); ca_mat_print(C, ctx); flint_printf("\n"); flint_abort(); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(C, ctx); } ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-diagonalization.c000066400000000000000000000052421407704557200211330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("diagonalization..."); fflush(stdout); flint_randinit(state); /* todo: test non-diagonalizable matrices */ /* todo: test aliasing */ for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, P, D, Pinv, B; slong n; truth_t result; ca_ctx_init(ctx); n = n_randint(state, 4); ca_mat_init(A, n, n, ctx); ca_mat_init(P, n, n, ctx); ca_mat_init(D, n, n, ctx); ca_mat_init(Pinv, n, n, ctx); ca_mat_init(B, n, n, ctx); if (n <= 2) ca_mat_randtest(A, state, 1, 5, ctx); else ca_mat_randtest_rational(A, state, 5, ctx); ca_mat_randtest(D, state, 1, 5, ctx); ca_mat_randtest(P, state, 1, 5, ctx); result = ca_mat_diagonalization(D, P, A, ctx); if (result == T_TRUE) { result = ca_mat_inv(Pinv, P, ctx); if (result == T_FALSE) { flint_printf("FAIL (inversion of P)\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("D: "); ca_mat_print(D, ctx); flint_printf("\n"); flint_printf("P: "); ca_mat_print(P, ctx); flint_printf("\n"); flint_abort(); } if (result == T_TRUE) { ca_mat_mul(B, P, D, ctx); ca_mat_mul(B, B, Pinv, ctx); result = ca_mat_check_equal(A, B, ctx); if (result == T_FALSE) { flint_printf("FAIL\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("D: "); ca_mat_print(D, ctx); flint_printf("\n"); flint_printf("P: "); ca_mat_print(P, ctx); flint_printf("\n"); flint_abort(); } } } ca_mat_clear(A, ctx); ca_mat_clear(D, ctx); ca_mat_clear(P, ctx); ca_mat_clear(Pinv, ctx); ca_mat_clear(B, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-exp.c000066400000000000000000000100201407704557200165410ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("exp..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B, P, Q, C, D; ca_t d, t; slong n; int success; ca_ctx_init(ctx); n = n_randint(state, 3); ca_mat_init(A, n, n, ctx); ca_mat_init(B, n, n, ctx); ca_mat_init(P, n, n, ctx); ca_mat_init(Q, n, n, ctx); ca_mat_init(C, n, n, ctx); ca_mat_init(D, n, n, ctx); ca_init(d, ctx); ca_init(t, ctx); if (n <= 2 && n_randint(state, 5) == 0) ca_mat_randtest(A, state, 1, 5, ctx); else ca_mat_randtest_rational(A, state, 5, ctx); if (n_randint(state, 2)) { success = ca_mat_exp(B, A, ctx); } else { ca_mat_set(B, A, ctx); success = ca_mat_exp(B, B, ctx); } if (success) { ca_mat_det(d, B, ctx); ca_mat_trace(t, A, ctx); ca_exp(t, t, ctx); if (ca_check_equal(d, t, ctx) == T_FALSE) { flint_printf("FAIL (trace)\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B: "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("d: "); ca_print(d, ctx); flint_printf("\n"); flint_printf("t: "); ca_print(t, ctx); flint_printf("\n"); flint_abort(); } do { ca_mat_randtest_rational(P, state, 1, ctx); } while (ca_mat_inv(Q, P, ctx) != T_TRUE); ca_mat_mul(C, P, A, ctx); ca_mat_mul(C, C, Q, ctx); success = ca_mat_exp(C, C, ctx); if (success) { ca_mat_mul(D, P, B, ctx); ca_mat_mul(D, D, Q, ctx); if (ca_mat_check_equal(C, D, ctx) == T_FALSE) { flint_printf("FAIL (similarity transform)\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B: "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("C: "); ca_mat_print(C, ctx); flint_printf("\n"); flint_printf("D: "); ca_mat_print(D, ctx); flint_printf("\n"); flint_printf("P: "); ca_mat_print(P, ctx); flint_printf("\n"); flint_printf("Q: "); ca_mat_print(Q, ctx); flint_printf("\n"); flint_abort(); } } } if (ca_mat_log(B, A, ctx) == T_TRUE) { success = ca_mat_exp(C, B, ctx); if (success) { if (ca_mat_check_equal(A, C, ctx) == T_FALSE) { flint_printf("FAIL (logarithm)\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B: "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("C: "); ca_mat_print(C, ctx); flint_printf("\n"); flint_abort(); } } } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(P, ctx); ca_mat_clear(Q, ctx); ca_mat_clear(C, ctx); ca_mat_clear(D, ctx); ca_clear(d, ctx); ca_clear(t, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-inv.c000066400000000000000000000043771407704557200165630ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("inv...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B, C; slong n; truth_t success; ca_ctx_init(ctx); n = n_randint(state, 6); ca_mat_init(A, n, n, ctx); ca_mat_init(B, n, n, ctx); ca_mat_init(C, n, n, ctx); if (n_randint(state, 2) || n > 3) ca_mat_randtest_rational(A, state, 5, ctx); else ca_mat_randtest(A, state, 1, 5, ctx); success = ca_mat_inv(B, A, ctx); if (success == T_TRUE) { ca_mat_mul(C, A, B, ctx); if (ca_mat_check_is_one(C, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("C = "); ca_mat_print(C, ctx); flint_printf("\n"); flint_abort(); } } else if (success == T_FALSE) { ca_t det; ca_init(det, ctx); ca_mat_det(det, A, ctx); if (ca_check_is_zero(det, ctx) == T_FALSE) { flint_printf("FAIL (singular)\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("det = "); ca_print(det, ctx); flint_printf("\n"); flint_abort(); } ca_clear(det, ctx); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(C, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-jordan_blocks.c000066400000000000000000000173201407704557200205710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int check_jordan_forms(ca_vec_t lambda1, slong num_blocks1, slong * block_lambda1, slong * block_size1, ca_vec_t lambda2, slong num_blocks2, slong * block_lambda2, slong * block_size2, ca_ctx_t ctx) { slong i, j; slong * used; slong found; int result; if (num_blocks1 != num_blocks2) return 0; if (ca_vec_length(lambda1, ctx) != ca_vec_length(lambda2, ctx)) return 0; /* note: not ordered for (i = 0; i < ca_vec_length(lambda1, ctx); i++) if (ca_check_equal(ca_vec_entry(lambda1, i), ca_vec_entry(lambda2, i), ctx) == T_FALSE) return 0; */ used = flint_calloc(sizeof(slong), num_blocks1); result = 1; for (i = 0; result && i < num_blocks1; i++) { found = -1; for (j = 0; found == -1 && j < num_blocks2; j++) { if (!used[j]) { if (/* block_lambda1[i] == block_lambda2[j] -- if ordered */ ca_check_equal(ca_vec_entry(lambda1, block_lambda1[i]), ca_vec_entry(lambda2, block_lambda2[j]), ctx) != T_FALSE && block_size1[i] == block_size2[j]) { found = j; used[j] = 1; } } } if (found == -1) result = 0; } flint_free(used); return result; } int main() { slong iter; flint_rand_t state; flint_printf("jordan_blocks..."); fflush(stdout); flint_randinit(state); /* Test J(A) = J(P * A * P^-1) for random rational Jordan block matrix A and random P */ for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, P, Q, B; slong n, i, j, num_lambda; int success1, success2; slong num_blocks1, num_blocks2, offset; ca_vec_t lambda1, lambda2; slong *block_lambda1, *block_size1, *block_lambda2, *block_size2; ca_ctx_init(ctx); num_lambda = 1 + n_randint(state, 3); ca_vec_init(lambda1, num_lambda, ctx); offset = n_randint(state, 2); for (i = 0; i < num_lambda; i++) ca_set_ui(ca_vec_entry(lambda1, i), offset + i, ctx); block_lambda1 = flint_malloc(sizeof(slong) * 4 * num_lambda); block_size1 = flint_malloc(sizeof(slong) * 4 * num_lambda); num_blocks1 = 0; n = 0; for (i = 0; i < num_lambda; i++) { slong blocks = 1 + n_randint(state, 3); for (j = 0; j < blocks; j++) { block_size1[num_blocks1] = 1 + n_randint(state, 3); block_lambda1[num_blocks1] = i; n += block_size1[num_blocks1]; num_blocks1++; } } ca_mat_init(A, n, n, ctx); ca_mat_init(P, n, n, ctx); ca_mat_init(Q, n, n, ctx); ca_mat_init(B, n, n, ctx); ca_vec_init(lambda2, 0, ctx); block_lambda2 = flint_malloc(sizeof(slong) * n); block_size2 = flint_malloc(sizeof(slong) * n); ca_mat_set_jordan_blocks(A, lambda1, num_blocks1, block_lambda1, block_size1, ctx); do { ca_mat_randtest_rational(P, state, 1, ctx); } while (ca_mat_inv(Q, P, ctx) != T_TRUE); ca_mat_mul(B, P, A, ctx); ca_mat_mul(B, B, Q, ctx); success1 = 1; success2 = ca_mat_jordan_blocks(lambda2, &num_blocks2, block_lambda2, block_size2, B, ctx); if (success1 && success2) { if (!check_jordan_forms(lambda1, num_blocks1, block_lambda1, block_size1, lambda2, num_blocks2, block_lambda2, block_size2, ctx)) { flint_printf("FAIL (different Jordan forms)\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B: "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("lambda1: "); ca_vec_print(lambda1, ctx); printf("\n"); flint_printf("lambda2: "); ca_vec_print(lambda2, ctx); printf("\n"); flint_abort(); } } else { flint_printf("FAIL (unexpected failure to compute Jordan blocks in rational case)\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("lambda1: "); ca_vec_print(lambda1, ctx); printf("\n"); flint_abort(); } ca_mat_clear(A, ctx); ca_mat_clear(P, ctx); ca_mat_clear(Q, ctx); ca_mat_clear(B, ctx); ca_vec_clear(lambda1, ctx); ca_vec_clear(lambda2, ctx); flint_free(block_lambda1); flint_free(block_lambda2); flint_free(block_size1); flint_free(block_size2); ca_ctx_clear(ctx); } /* Test J(A) = J(P * A * P^-1) for random A, P */ for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, P, Q, B; slong n; int success1, success2; slong num_blocks1, num_blocks2; ca_vec_t lambda1, lambda2; slong *block_lambda1, *block_size1, *block_lambda2, *block_size2; n = n_randint(state, 6); ca_ctx_init(ctx); ca_mat_init(A, n, n, ctx); ca_mat_init(P, n, n, ctx); ca_mat_init(Q, n, n, ctx); ca_mat_init(B, n, n, ctx); ca_vec_init(lambda1, 0, ctx); ca_vec_init(lambda2, 0, ctx); block_lambda1 = flint_malloc(sizeof(slong) * n); block_lambda2 = flint_malloc(sizeof(slong) * n); block_size1 = flint_malloc(sizeof(slong) * n); block_size2 = flint_malloc(sizeof(slong) * n); if (n <= 3 && n_randint(state, 2) == 0) ca_mat_randtest(A, state, 1, 5, ctx); else ca_mat_randtest_rational(A, state, 5, ctx); do { ca_mat_randtest_rational(P, state, 1, ctx); } while (ca_mat_inv(Q, P, ctx) != T_TRUE); ca_mat_mul(B, P, A, ctx); ca_mat_mul(B, B, Q, ctx); success1 = ca_mat_jordan_blocks(lambda1, &num_blocks1, block_lambda1, block_size1, A, ctx); success2 = success1 && ca_mat_jordan_blocks(lambda2, &num_blocks2, block_lambda2, block_size2, B, ctx); if (success1 && success2) { if (!check_jordan_forms(lambda1, num_blocks1, block_lambda1, block_size1, lambda2, num_blocks2, block_lambda2, block_size2, ctx)) { flint_printf("FAIL (different jordan forms)\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B: "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("lambda1: "); ca_vec_print(lambda1, ctx); printf("\n"); flint_printf("lambda2: "); ca_vec_print(lambda2, ctx); printf("\n"); flint_abort(); } } ca_mat_clear(A, ctx); ca_mat_clear(P, ctx); ca_mat_clear(Q, ctx); ca_mat_clear(B, ctx); ca_vec_clear(lambda1, ctx); ca_vec_clear(lambda2, ctx); flint_free(block_lambda1); flint_free(block_lambda2); flint_free(block_size1); flint_free(block_size2); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-jordan_form.c000066400000000000000000000136721407704557200202650ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("jordan_form..."); fflush(stdout); flint_randinit(state); /* Test P J P^{-1} = A for random matrices A generated from Jordan blocks */ for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, P, Q, B, J; slong n, i, j, num_lambda; int success; slong num_blocks1, offset; ca_vec_t lambda1; slong *block_lambda1, *block_size1; truth_t inv; ca_ctx_init(ctx); num_lambda = 1 + n_randint(state, 3); ca_vec_init(lambda1, num_lambda, ctx); offset = n_randint(state, 2); for (i = 0; i < num_lambda; i++) ca_set_ui(ca_vec_entry(lambda1, i), offset + i, ctx); block_lambda1 = flint_malloc(sizeof(slong) * 4 * num_lambda); block_size1 = flint_malloc(sizeof(slong) * 4 * num_lambda); num_blocks1 = 0; n = 0; for (i = 0; i < num_lambda; i++) { slong blocks = 1 + n_randint(state, 3); for (j = 0; j < blocks; j++) { block_size1[num_blocks1] = 1 + n_randint(state, 3); block_lambda1[num_blocks1] = i; n += block_size1[num_blocks1]; num_blocks1++; } } ca_mat_init(A, n, n, ctx); ca_mat_init(P, n, n, ctx); ca_mat_init(Q, n, n, ctx); ca_mat_init(B, n, n, ctx); ca_mat_init(J, n, n, ctx); ca_mat_set_jordan_blocks(A, lambda1, num_blocks1, block_lambda1, block_size1, ctx); do { ca_mat_randtest_rational(P, state, 1, ctx); } while (ca_mat_inv(Q, P, ctx) != T_TRUE); ca_mat_mul(B, P, A, ctx); ca_mat_mul(B, B, Q, ctx); ca_mat_zero(P, ctx); ca_mat_zero(Q, ctx); success = ca_mat_jordan_form(J, P, A, ctx); if (success) { inv = ca_mat_inv(Q, P, ctx); if (inv == T_FALSE) { flint_printf("FAIL (matrix not invertible)\n"); flint_printf("A: "); ca_mat_printn(A, 5, ctx); flint_printf("\n"); flint_printf("J: "); ca_mat_printn(J, 5, ctx); flint_printf("\n"); flint_printf("P: "); ca_mat_printn(P, 5, ctx); flint_printf("\n"); flint_abort(); } ca_mat_mul(B, P, J, ctx); ca_mat_mul(B, B, Q, ctx); if (ca_mat_check_equal(B, A, ctx) == T_FALSE) { flint_printf("FAIL\n"); flint_printf("A: "); ca_mat_printn(A, 5, ctx); flint_printf("\n"); flint_printf("B: "); ca_mat_printn(B, 5, ctx); flint_printf("\n"); flint_printf("J: "); ca_mat_printn(J, 5, ctx); flint_printf("\n"); flint_printf("P: "); ca_mat_printn(P, 5, ctx); flint_printf("\n"); flint_printf("Q: "); ca_mat_printn(Q, 5, ctx); flint_printf("\n"); flint_abort(); } } ca_mat_clear(A, ctx); ca_mat_clear(P, ctx); ca_mat_clear(Q, ctx); ca_mat_clear(B, ctx); ca_mat_clear(J, ctx); ca_vec_clear(lambda1, ctx); flint_free(block_lambda1); flint_free(block_size1); ca_ctx_clear(ctx); } /* Test P J P^{-1} = A for random matrices A */ for (iter = 0; iter < 500 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B, J, P, Q; slong n; int success; truth_t inv; n = n_randint(state, 5); ca_ctx_init(ctx); ca_mat_init(A, n, n, ctx); ca_mat_init(B, n, n, ctx); ca_mat_init(J, n, n, ctx); ca_mat_init(P, n, n, ctx); ca_mat_init(Q, n, n, ctx); if (n <= 2 && n_randint(state, 2) == 0) ca_mat_randtest(A, state, 1, 5, ctx); else ca_mat_randtest_rational(A, state, 5, ctx); /* test aliasing */ if (n_randint(state, 2)) success = ca_mat_jordan_form(J, P, A, ctx); else { ca_mat_set(P, A, ctx); success = ca_mat_jordan_form(J, P, P, ctx); } if (success) { inv = ca_mat_inv(Q, P, ctx); if (inv == T_FALSE) { flint_printf("FAIL (matrix not invertible)\n"); flint_printf("A: "); ca_mat_printn(A, 5, ctx); flint_printf("\n"); flint_printf("J: "); ca_mat_printn(J, 5, ctx); flint_printf("\n"); flint_printf("P: "); ca_mat_printn(P, 5, ctx); flint_printf("\n"); flint_abort(); } ca_mat_mul(B, P, J, ctx); ca_mat_mul(B, B, Q, ctx); if (ca_mat_check_equal(B, A, ctx) == T_FALSE) { flint_printf("FAIL\n"); flint_printf("A: "); ca_mat_printn(A, 5, ctx); flint_printf("\n"); flint_printf("B: "); ca_mat_printn(B, 5, ctx); flint_printf("\n"); flint_printf("J: "); ca_mat_printn(J, 5, ctx); flint_printf("\n"); flint_printf("P: "); ca_mat_printn(P, 5, ctx); flint_printf("\n"); flint_printf("Q: "); ca_mat_printn(Q, 5, ctx); flint_printf("\n"); flint_abort(); } } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(J, ctx); ca_mat_clear(P, ctx); ca_mat_clear(Q, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-lu.c000066400000000000000000000074721407704557200164060ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void perm(ca_mat_t A, slong * P) { slong i; ca_struct ** tmp; if (A->c == 0 || A->r == 0) return; tmp = flint_malloc(sizeof(ca_struct *) * A->r); for (i = 0; i < A->r; i++) tmp[P[i]] = A->rows[i]; for (i = 0; i < A->r; i++) A->rows[i] = tmp[i]; flint_free(tmp); } void check(slong * P, ca_mat_t LU, const ca_mat_t A, slong rank, ca_ctx_t ctx) { ca_mat_t B, L, U; slong m, n, i, j; m = A->r; n = A->c; ca_mat_init(B, m, n, ctx); ca_mat_init(L, m, m, ctx); ca_mat_init(U, m, n, ctx); rank = FLINT_ABS(rank); for (i = rank; i < FLINT_MIN(m, n); i++) { for (j = i; j < n; j++) { if (ca_check_is_zero(ca_mat_entry(LU, i, j), ctx) != T_TRUE) { flint_printf("FAIL: wrong shape!\n"); flint_abort(); } } } for (i = 0; i < m; i++) { for (j = 0; j < FLINT_MIN(i, n); j++) ca_set(ca_mat_entry(L, i, j), ca_mat_entry(LU, i, j), ctx); if (i < rank) ca_one(ca_mat_entry(L, i, i), ctx); for (j = i; j < n; j++) ca_set(ca_mat_entry(U, i, j), ca_mat_entry(LU, i, j), ctx); } ca_mat_mul(B, L, U, ctx); perm(B, P); if (ca_mat_check_equal(A, B, ctx) == T_FALSE) { flint_printf("FAIL\n"); flint_printf("A:\n"); ca_mat_print(A, ctx); flint_printf("LU:\n"); ca_mat_print(LU, ctx); flint_printf("B:\n"); ca_mat_print(B, ctx); flint_abort(); } ca_mat_clear(B, ctx); ca_mat_clear(L, ctx); ca_mat_clear(U, ctx); } void ca_mat_randrank(ca_mat_t mat, flint_rand_t state, slong rank, slong bits, ca_ctx_t ctx) { fmpz_mat_t A; fmpz_mat_init(A, mat->r, mat->c); fmpz_mat_randrank(A, state, rank, bits); ca_mat_set_fmpz_mat(mat, A, ctx); fmpz_mat_clear(A); } int main() { slong iter; flint_rand_t state; flint_printf("lu..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, LU; slong m, n, r, d, rank; slong * P; int success; ca_ctx_init(ctx); m = n_randint(state, 10); n = n_randint(state, 10); for (r = 0; r <= FLINT_MIN(m, n); r++) { ca_mat_init(A, m, n, ctx); ca_mat_init(LU, m, n, ctx); ca_mat_randrank(A, state, r, 5, ctx); if (n_randint(state, 2)) { d = n_randint(state, 2*m*n + 1); ca_mat_randops(A, state, d, ctx); } P = flint_malloc(sizeof(slong) * m); success = ca_mat_lu(&rank, P, LU, A, 0, ctx); if (success) { if (r != rank) { flint_printf("FAIL:\n"); flint_printf("wrong rank!\n"); flint_printf("A:"); ca_mat_print(A, ctx); flint_printf("LU:"); ca_mat_print(LU, ctx); flint_abort(); } check(P, LU, A, rank, ctx); } ca_mat_clear(A, ctx); ca_mat_clear(LU, ctx); flint_free(P); } ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-lu_classical.c000066400000000000000000000075161407704557200204230ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void perm(ca_mat_t A, slong * P) { slong i; ca_struct ** tmp; if (A->c == 0 || A->r == 0) return; tmp = flint_malloc(sizeof(ca_struct *) * A->r); for (i = 0; i < A->r; i++) tmp[P[i]] = A->rows[i]; for (i = 0; i < A->r; i++) A->rows[i] = tmp[i]; flint_free(tmp); } void check(slong * P, ca_mat_t LU, const ca_mat_t A, slong rank, ca_ctx_t ctx) { ca_mat_t B, L, U; slong m, n, i, j; m = A->r; n = A->c; ca_mat_init(B, m, n, ctx); ca_mat_init(L, m, m, ctx); ca_mat_init(U, m, n, ctx); rank = FLINT_ABS(rank); for (i = rank; i < FLINT_MIN(m, n); i++) { for (j = i; j < n; j++) { if (ca_check_is_zero(ca_mat_entry(LU, i, j), ctx) != T_TRUE) { flint_printf("FAIL: wrong shape!\n"); flint_abort(); } } } for (i = 0; i < m; i++) { for (j = 0; j < FLINT_MIN(i, n); j++) ca_set(ca_mat_entry(L, i, j), ca_mat_entry(LU, i, j), ctx); if (i < rank) ca_one(ca_mat_entry(L, i, i), ctx); for (j = i; j < n; j++) ca_set(ca_mat_entry(U, i, j), ca_mat_entry(LU, i, j), ctx); } ca_mat_mul(B, L, U, ctx); perm(B, P); if (ca_mat_check_equal(A, B, ctx) == T_FALSE) { flint_printf("FAIL\n"); flint_printf("A:\n"); ca_mat_print(A, ctx); flint_printf("LU:\n"); ca_mat_print(LU, ctx); flint_printf("B:\n"); ca_mat_print(B, ctx); flint_abort(); } ca_mat_clear(B, ctx); ca_mat_clear(L, ctx); ca_mat_clear(U, ctx); } void ca_mat_randrank(ca_mat_t mat, flint_rand_t state, slong rank, slong bits, ca_ctx_t ctx) { fmpz_mat_t A; fmpz_mat_init(A, mat->r, mat->c); fmpz_mat_randrank(A, state, rank, bits); ca_mat_set_fmpz_mat(mat, A, ctx); fmpz_mat_clear(A); } int main() { slong iter; flint_rand_t state; flint_printf("lu_classical..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, LU; slong m, n, r, d, rank; slong * P; int success; ca_ctx_init(ctx); m = n_randint(state, 10); n = n_randint(state, 10); for (r = 0; r <= FLINT_MIN(m, n); r++) { ca_mat_init(A, m, n, ctx); ca_mat_init(LU, m, n, ctx); ca_mat_randrank(A, state, r, 5, ctx); if (n_randint(state, 2)) { d = n_randint(state, 2*m*n + 1); ca_mat_randops(A, state, d, ctx); } P = flint_malloc(sizeof(slong) * m); success = ca_mat_lu_classical(&rank, P, LU, A, 0, ctx); if (success) { if (r != rank) { flint_printf("FAIL:\n"); flint_printf("wrong rank!\n"); flint_printf("A:"); ca_mat_print(A, ctx); flint_printf("LU:"); ca_mat_print(LU, ctx); flint_abort(); } check(P, LU, A, rank, ctx); } ca_mat_clear(A, ctx); ca_mat_clear(LU, ctx); flint_free(P); } ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-lu_recursive.c000066400000000000000000000075161407704557200204740ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void perm(ca_mat_t A, slong * P) { slong i; ca_struct ** tmp; if (A->c == 0 || A->r == 0) return; tmp = flint_malloc(sizeof(ca_struct *) * A->r); for (i = 0; i < A->r; i++) tmp[P[i]] = A->rows[i]; for (i = 0; i < A->r; i++) A->rows[i] = tmp[i]; flint_free(tmp); } void check(slong * P, ca_mat_t LU, const ca_mat_t A, slong rank, ca_ctx_t ctx) { ca_mat_t B, L, U; slong m, n, i, j; m = A->r; n = A->c; ca_mat_init(B, m, n, ctx); ca_mat_init(L, m, m, ctx); ca_mat_init(U, m, n, ctx); rank = FLINT_ABS(rank); for (i = rank; i < FLINT_MIN(m, n); i++) { for (j = i; j < n; j++) { if (ca_check_is_zero(ca_mat_entry(LU, i, j), ctx) != T_TRUE) { flint_printf("FAIL: wrong shape!\n"); flint_abort(); } } } for (i = 0; i < m; i++) { for (j = 0; j < FLINT_MIN(i, n); j++) ca_set(ca_mat_entry(L, i, j), ca_mat_entry(LU, i, j), ctx); if (i < rank) ca_one(ca_mat_entry(L, i, i), ctx); for (j = i; j < n; j++) ca_set(ca_mat_entry(U, i, j), ca_mat_entry(LU, i, j), ctx); } ca_mat_mul(B, L, U, ctx); perm(B, P); if (ca_mat_check_equal(A, B, ctx) == T_FALSE) { flint_printf("FAIL\n"); flint_printf("A:\n"); ca_mat_print(A, ctx); flint_printf("LU:\n"); ca_mat_print(LU, ctx); flint_printf("B:\n"); ca_mat_print(B, ctx); flint_abort(); } ca_mat_clear(B, ctx); ca_mat_clear(L, ctx); ca_mat_clear(U, ctx); } void ca_mat_randrank(ca_mat_t mat, flint_rand_t state, slong rank, slong bits, ca_ctx_t ctx) { fmpz_mat_t A; fmpz_mat_init(A, mat->r, mat->c); fmpz_mat_randrank(A, state, rank, bits); ca_mat_set_fmpz_mat(mat, A, ctx); fmpz_mat_clear(A); } int main() { slong iter; flint_rand_t state; flint_printf("lu_recursive..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, LU; slong m, n, r, d, rank; slong * P; int success; ca_ctx_init(ctx); m = n_randint(state, 10); n = n_randint(state, 10); for (r = 0; r <= FLINT_MIN(m, n); r++) { ca_mat_init(A, m, n, ctx); ca_mat_init(LU, m, n, ctx); ca_mat_randrank(A, state, r, 5, ctx); if (n_randint(state, 2)) { d = n_randint(state, 2*m*n + 1); ca_mat_randops(A, state, d, ctx); } P = flint_malloc(sizeof(slong) * m); success = ca_mat_lu_recursive(&rank, P, LU, A, 0, ctx); if (success) { if (r != rank) { flint_printf("FAIL:\n"); flint_printf("wrong rank!\n"); flint_printf("A:"); ca_mat_print(A, ctx); flint_printf("LU:"); ca_mat_print(LU, ctx); flint_abort(); } check(P, LU, A, rank, ctx); } ca_mat_clear(A, ctx); ca_mat_clear(LU, ctx); flint_free(P); } ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-mul.c000066400000000000000000000104721407704557200165550ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("mul...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B, C, AB, BC, X, Y; slong M, N, K, L; /* Test (A*B)*C = A*(B*C) */ M = n_randint(state, 4); N = n_randint(state, 4); K = n_randint(state, 4); L = n_randint(state, 4); ca_ctx_init(ctx); ca_mat_init(A, M, N, ctx); ca_mat_init(B, N, K, ctx); ca_mat_init(C, K, L, ctx); ca_mat_init(AB, M, K, ctx); ca_mat_init(BC, N, L, ctx); ca_mat_init(X, M, L, ctx); ca_mat_init(Y, M, L, ctx); ca_mat_randtest(A, state, 2, 10, ctx); ca_mat_randtest(B, state, 2, 10, ctx); ca_mat_randtest(C, state, 2, 10, ctx); ca_mat_randtest(AB, state, 2, 10, ctx); ca_mat_randtest(BC, state, 2, 10, ctx); ca_mat_randtest(X, state, 2, 10, ctx); ca_mat_randtest(Y, state, 2, 10, ctx); ca_mat_mul(AB, A, B, ctx); ca_mat_mul(X, AB, C, ctx); ca_mat_mul(BC, B, C, ctx); ca_mat_mul(Y, A, BC, ctx); if (ca_mat_check_equal(X, Y, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("C = "); ca_mat_print(C, ctx); flint_printf("\n"); flint_printf("X = "); ca_mat_print(X, ctx); flint_printf("\n"); flint_printf("Y = "); ca_mat_print(Y, ctx); flint_printf("\n"); flint_abort(); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(C, ctx); ca_mat_clear(AB, ctx); ca_mat_clear(BC, ctx); ca_mat_clear(X, ctx); ca_mat_clear(Y, ctx); ca_ctx_clear(ctx); } for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B, C, AB, BC, X, Y; slong M, N, K, L; /* Test (A*B)*C = A*(B*C), rational matrices */ M = n_randint(state, 5); N = n_randint(state, 5); K = n_randint(state, 5); L = n_randint(state, 5); ca_ctx_init(ctx); ca_mat_init(A, M, N, ctx); ca_mat_init(B, N, K, ctx); ca_mat_init(C, K, L, ctx); ca_mat_init(AB, M, K, ctx); ca_mat_init(BC, N, L, ctx); ca_mat_init(X, M, L, ctx); ca_mat_init(Y, M, L, ctx); ca_mat_randtest_rational(A, state, 200, ctx); ca_mat_randtest_rational(B, state, 200, ctx); ca_mat_randtest_rational(C, state, 200, ctx); ca_mat_randtest_rational(AB, state, 200, ctx); ca_mat_randtest_rational(BC, state, 200, ctx); ca_mat_randtest_rational(X, state, 200, ctx); ca_mat_randtest_rational(Y, state, 200, ctx); ca_mat_mul(AB, A, B, ctx); ca_mat_mul(X, AB, C, ctx); ca_mat_mul(BC, B, C, ctx); ca_mat_mul(Y, A, BC, ctx); if (ca_mat_check_equal(X, Y, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("C = "); ca_mat_print(C, ctx); flint_printf("\n"); flint_printf("X = "); ca_mat_print(X, ctx); flint_printf("\n"); flint_printf("Y = "); ca_mat_print(Y, ctx); flint_printf("\n"); flint_abort(); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(C, ctx); ca_mat_clear(AB, ctx); ca_mat_clear(BC, ctx); ca_mat_clear(X, ctx); ca_mat_clear(Y, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-mul_same_nf.c000066400000000000000000000061201407704557200202400ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_randtest_same_nf(ca_mat_t res, flint_rand_t state, const ca_t x, slong bits, slong den_bits, ca_ctx_t ctx) { slong i, j; fmpz_t t; for (i = 0; i < ca_mat_nrows(res); i++) for (j = 0; j < ca_mat_ncols(res); j++) ca_randtest_same_nf(ca_mat_entry(res, i, j), state, x, bits, 1, ctx); fmpz_init(t); fmpz_randtest_not_zero(t, state, den_bits); ca_mat_div_fmpz(res, res, t, ctx); fmpz_clear(t); } int main() { slong iter; flint_rand_t state; flint_printf("mul_same_nf...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B, C, D; qqbar_t t; ca_t x; slong m, n, k; ca_field_ptr K; /* Test (A*B)*C = A*(B*C) */ m = n_randint(state, 5); n = n_randint(state, 5); k = n_randint(state, 5); ca_ctx_init(ctx); qqbar_init(t); ca_init(x, ctx); do { qqbar_randtest(t, state, 8, 10); } while (qqbar_is_rational(t)); ca_set_qqbar(x, t, ctx); ca_mat_init(A, m, n, ctx); ca_mat_init(B, n, k, ctx); ca_mat_init(C, m, k, ctx); ca_mat_init(D, m, k, ctx); ca_mat_randtest_same_nf(A, state, x, 10, 10, ctx); ca_mat_randtest_same_nf(B, state, x, 10, 10, ctx); ca_mat_randtest(C, state, 1, 5, ctx); ca_mat_randtest(D, state, 1, 5, ctx); K = _ca_mat_same_field(A, ctx); if (K != NULL && CA_FIELD_IS_NF(K)) { if (n_randint(state, 2) && (m == n && n == k)) { /* test aliasing */ ca_mat_set(C, A, ctx); ca_mat_mul_same_nf(C, C, B, K, ctx); } else { ca_mat_mul_same_nf(C, A, B, K, ctx); } ca_mat_mul_classical(D, A, B, ctx); if (ca_mat_check_equal(C, D, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("C = "); ca_mat_print(C, ctx); flint_printf("\n"); flint_printf("D = "); ca_mat_print(D, ctx); flint_printf("\n"); flint_abort(); } } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(C, ctx); ca_mat_clear(D, ctx); ca_clear(x, ctx); qqbar_clear(t); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-nonsingular_solve.c000066400000000000000000000052701407704557200215270ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("nonsingular_solve...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, X, B, AX; slong n, c; truth_t success; ca_ctx_init(ctx); n = n_randint(state, 6); c = n_randint(state, 6); ca_mat_init(A, n, n, ctx); ca_mat_init(B, n, c, ctx); ca_mat_init(X, n, c, ctx); ca_mat_init(AX, n, c, ctx); if (n_randint(state, 2) || n > 3) ca_mat_randtest_rational(A, state, 5, ctx); else ca_mat_randtest(A, state, 1, 5, ctx); ca_mat_randtest(X, state, 1, 5, ctx); if (n_randint(state, 2) || n > 3) ca_mat_randtest_rational(B, state, 5, ctx); else ca_mat_randtest(B, state, 1, 5, ctx); success = ca_mat_nonsingular_solve(X, A, B, ctx); if (success == T_TRUE) { ca_mat_mul(AX, A, X, ctx); if (ca_mat_check_equal(AX, B, ctx) == T_FALSE) { flint_printf("FAIL (solve)\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("X = "); ca_mat_print(X, ctx); flint_printf("\n"); flint_printf("AX = "); ca_mat_print(AX, ctx); flint_printf("\n"); flint_abort(); } } else if (success == T_FALSE) { ca_t det; ca_init(det, ctx); ca_mat_det(det, A, ctx); if (ca_check_is_zero(det, ctx) == T_FALSE) { flint_printf("FAIL (singular)\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("det = "); ca_print(det, ctx); flint_printf("\n"); flint_abort(); } ca_clear(det, ctx); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(X, ctx); ca_mat_clear(AX, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-nonsingular_solve_adjugate.c000066400000000000000000000053121407704557200233700ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("nonsingular_solve_adjugate...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, X, B, AX; slong n, c; truth_t success; ca_ctx_init(ctx); n = n_randint(state, 6); c = n_randint(state, 6); ca_mat_init(A, n, n, ctx); ca_mat_init(B, n, c, ctx); ca_mat_init(X, n, c, ctx); ca_mat_init(AX, n, c, ctx); if (n_randint(state, 2) || n > 3) ca_mat_randtest_rational(A, state, 5, ctx); else ca_mat_randtest(A, state, 1, 5, ctx); ca_mat_randtest(X, state, 1, 5, ctx); if (n_randint(state, 2) || n > 3) ca_mat_randtest_rational(B, state, 5, ctx); else ca_mat_randtest(B, state, 1, 5, ctx); success = ca_mat_nonsingular_solve_adjugate(X, A, B, ctx); if (success == T_TRUE) { ca_mat_mul(AX, A, X, ctx); if (ca_mat_check_equal(AX, B, ctx) == T_FALSE) { flint_printf("FAIL (solve)\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("X = "); ca_mat_print(X, ctx); flint_printf("\n"); flint_printf("AX = "); ca_mat_print(AX, ctx); flint_printf("\n"); flint_abort(); } } else if (success == T_FALSE) { ca_t det; ca_init(det, ctx); ca_mat_det(det, A, ctx); if (ca_check_is_zero(det, ctx) == T_FALSE) { flint_printf("FAIL (singular)\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("det = "); ca_print(det, ctx); flint_printf("\n"); flint_abort(); } ca_clear(det, ctx); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(X, ctx); ca_mat_clear(AX, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-nonsingular_solve_fflu.c000066400000000000000000000053021407704557200225370ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("nonsingular_solve_fflu...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, X, B, AX; slong n, c; truth_t success; ca_ctx_init(ctx); n = n_randint(state, 6); c = n_randint(state, 6); ca_mat_init(A, n, n, ctx); ca_mat_init(B, n, c, ctx); ca_mat_init(X, n, c, ctx); ca_mat_init(AX, n, c, ctx); if (n_randint(state, 2) || n > 3) ca_mat_randtest_rational(A, state, 5, ctx); else ca_mat_randtest(A, state, 1, 5, ctx); ca_mat_randtest(X, state, 1, 5, ctx); if (n_randint(state, 2) || n > 3) ca_mat_randtest_rational(B, state, 5, ctx); else ca_mat_randtest(B, state, 1, 5, ctx); success = ca_mat_nonsingular_solve_fflu(X, A, B, ctx); if (success == T_TRUE) { ca_mat_mul(AX, A, X, ctx); if (ca_mat_check_equal(AX, B, ctx) == T_FALSE) { flint_printf("FAIL (solve)\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("X = "); ca_mat_print(X, ctx); flint_printf("\n"); flint_printf("AX = "); ca_mat_print(AX, ctx); flint_printf("\n"); flint_abort(); } } else if (success == T_FALSE) { ca_t det; ca_init(det, ctx); ca_mat_det(det, A, ctx); if (ca_check_is_zero(det, ctx) == T_FALSE) { flint_printf("FAIL (singular)\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("det = "); ca_print(det, ctx); flint_printf("\n"); flint_abort(); } ca_clear(det, ctx); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(X, ctx); ca_mat_clear(AX, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-nonsingular_solve_lu.c000066400000000000000000000052761407704557200222350ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("nonsingular_solve_lu...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, X, B, AX; slong n, c; truth_t success; ca_ctx_init(ctx); n = n_randint(state, 6); c = n_randint(state, 6); ca_mat_init(A, n, n, ctx); ca_mat_init(B, n, c, ctx); ca_mat_init(X, n, c, ctx); ca_mat_init(AX, n, c, ctx); if (n_randint(state, 2) || n > 3) ca_mat_randtest_rational(A, state, 5, ctx); else ca_mat_randtest(A, state, 1, 5, ctx); ca_mat_randtest(X, state, 1, 5, ctx); if (n_randint(state, 2) || n > 3) ca_mat_randtest_rational(B, state, 5, ctx); else ca_mat_randtest(B, state, 1, 5, ctx); success = ca_mat_nonsingular_solve_lu(X, A, B, ctx); if (success == T_TRUE) { ca_mat_mul(AX, A, X, ctx); if (ca_mat_check_equal(AX, B, ctx) == T_FALSE) { flint_printf("FAIL (solve)\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("X = "); ca_mat_print(X, ctx); flint_printf("\n"); flint_printf("AX = "); ca_mat_print(AX, ctx); flint_printf("\n"); flint_abort(); } } else if (success == T_FALSE) { ca_t det; ca_init(det, ctx); ca_mat_det(det, A, ctx); if (ca_check_is_zero(det, ctx) == T_FALSE) { flint_printf("FAIL (singular)\n\n"); flint_printf("A = "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("det = "); ca_print(det, ctx); flint_printf("\n"); flint_abort(); } ca_clear(det, ctx); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(X, ctx); ca_mat_clear(AX, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-rank.c000066400000000000000000000034171407704557200167140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("rank..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B; slong rank1, rank2, r, c; int success; ca_ctx_init(ctx); r = n_randint(state, 6); c = n_randint(state, 6); ca_mat_init(A, r, c, ctx); ca_mat_init(B, r, c, ctx); ca_mat_randtest(A, state, 1, 5, ctx); ca_mat_set(B, A, ctx); ca_mat_randops(B, state, 1 + n_randint(state, 20), ctx); success = ca_mat_rank(&rank1, A, ctx); if (success) { success = ca_mat_rank(&rank2, B, ctx); if (success) { if (rank1 != rank2) { flint_printf("FAIL:\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B: "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("rank = %wd, %wd\n\n", rank1, rank2); flint_abort(); } } } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-right_kernel.c000066400000000000000000000055301407704557200204340ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("right_kernel..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, X, AX; slong r, c, rank, nullity; int success, success2; ca_ctx_init(ctx); r = n_randint(state, 6); c = n_randint(state, 6); ca_mat_init(A, r, c, ctx); ca_mat_init(X, r, c, ctx); ca_mat_randtest(A, state, 1, 5, ctx); success = ca_mat_right_kernel(X, A, ctx); if (success) { success2 = ca_mat_rank(&rank, A, ctx); if (success2) { nullity = c - rank; if (nullity != ca_mat_ncols(X)) { flint_printf("FAIL:\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("X: "); ca_mat_print(X, ctx); flint_printf("\n"); flint_printf("rank = %wd, %wd\n\n", rank, nullity); flint_abort(); } ca_mat_init(AX, r, nullity, ctx); ca_mat_mul(AX, A, X, ctx); if (ca_mat_check_is_zero(AX, ctx) == T_FALSE) { flint_printf("FAIL:\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("X: "); ca_mat_print(X, ctx); flint_printf("\n"); flint_printf("AX: "); ca_mat_print(AX, ctx); flint_printf("\n"); flint_printf("rank = %wd, %wd\n\n", rank, nullity); flint_abort(); } success = ca_mat_rank(&nullity, X, ctx); if (!success || (nullity != ca_mat_ncols(X))) { flint_printf("FAIL (2):\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("X: "); ca_mat_print(X, ctx); flint_printf("\n"); flint_printf("rank = %wd, %wd\n\n", rank, nullity); flint_abort(); } ca_mat_clear(AX, ctx); } } ca_mat_clear(A, ctx); ca_mat_clear(X, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-rref.c000066400000000000000000000105011407704557200167070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_randrowops(ca_mat_t mat, flint_rand_t state, slong count, ca_ctx_t ctx) { slong c, i, j, k; slong m = mat->r; slong n = mat->c; if (mat->r == 0 || mat->c == 0) return; for (c = 0; c < count; c++) { if ((i = n_randint(state, m)) == (j = n_randint(state, m))) continue; if (n_randint(state, 2)) for (k = 0; k < n; k++) ca_add(ca_mat_entry(mat, j, k), ca_mat_entry(mat, j, k), ca_mat_entry(mat, i, k), ctx); else for (k = 0; k < n; k++) ca_sub(ca_mat_entry(mat, j, k), ca_mat_entry(mat, j, k), ca_mat_entry(mat, i, k), ctx); } } int main() { slong iter; flint_rand_t state; flint_printf("rref..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, R, R2; fmpq_mat_t AQ, RQ; slong rank, rankq, r, c; int success; ca_ctx_init(ctx); r = n_randint(state, 10); c = n_randint(state, 10); ca_mat_init(A, r, c, ctx); ca_mat_init(R, r, c, ctx); ca_mat_init(R2, r, c, ctx); fmpq_mat_init(AQ, r, c); fmpq_mat_init(RQ, r, c); fmpq_mat_randtest(AQ, state, 10); ca_mat_set_fmpq_mat(A, AQ, ctx); rankq = fmpq_mat_rref(RQ, AQ); if (n_randint(state, 2)) { ca_mat_set(R, A, ctx); success = ca_mat_rref(&rank, R, R, ctx); } else { success = ca_mat_rref(&rank, R, A, ctx); } if (success) { ca_mat_set_fmpq_mat(R2, RQ, ctx); if (rank != rankq || ca_mat_check_equal(R, R2, ctx) == T_FALSE) { flint_printf("FAIL:\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("R: "); ca_mat_print(R, ctx); flint_printf("\n"); flint_printf("R2: "); ca_mat_print(R2, ctx); flint_printf("\n"); flint_printf("rank = %wd, %wd\n\n", rank, rankq); flint_abort(); } } ca_mat_clear(A, ctx); ca_mat_clear(R, ctx); ca_mat_clear(R2, ctx); fmpq_mat_clear(AQ); fmpq_mat_clear(RQ); ca_ctx_clear(ctx); } for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B, R, R2; slong rank1, rank2, r, c; int success; ca_ctx_init(ctx); r = n_randint(state, 6); c = n_randint(state, 6); ca_mat_init(A, r, c, ctx); ca_mat_init(B, r, c, ctx); ca_mat_init(R, r, c, ctx); ca_mat_init(R2, r, c, ctx); ca_mat_randtest(A, state, 1, 5, ctx); ca_mat_set(B, A, ctx); ca_mat_randrowops(B, state, 1 + n_randint(state, 20), ctx); success = ca_mat_rref(&rank1, R, A, ctx); if (success) { success = ca_mat_rref(&rank2, R2, B, ctx); if (success) { if (rank1 != rank2 || ca_mat_check_equal(R, R2, ctx) == T_FALSE) { flint_printf("FAIL:\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B: "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("R: "); ca_mat_print(R, ctx); flint_printf("\n"); flint_printf("R2: "); ca_mat_print(R2, ctx); flint_printf("\n"); flint_printf("rank = %wd, %wd\n\n", rank1, rank2); flint_abort(); } } } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(R, ctx); ca_mat_clear(R2, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-rref_fflu.c000066400000000000000000000105321407704557200177270ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_randrowops(ca_mat_t mat, flint_rand_t state, slong count, ca_ctx_t ctx) { slong c, i, j, k; slong m = mat->r; slong n = mat->c; if (mat->r == 0 || mat->c == 0) return; for (c = 0; c < count; c++) { if ((i = n_randint(state, m)) == (j = n_randint(state, m))) continue; if (n_randint(state, 2)) for (k = 0; k < n; k++) ca_add(ca_mat_entry(mat, j, k), ca_mat_entry(mat, j, k), ca_mat_entry(mat, i, k), ctx); else for (k = 0; k < n; k++) ca_sub(ca_mat_entry(mat, j, k), ca_mat_entry(mat, j, k), ca_mat_entry(mat, i, k), ctx); } } int main() { slong iter; flint_rand_t state; flint_printf("rref_fflu..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, R, R2; fmpq_mat_t AQ, RQ; slong rank, rankq, r, c; int success; ca_ctx_init(ctx); r = n_randint(state, 10); c = n_randint(state, 10); ca_mat_init(A, r, c, ctx); ca_mat_init(R, r, c, ctx); ca_mat_init(R2, r, c, ctx); fmpq_mat_init(AQ, r, c); fmpq_mat_init(RQ, r, c); fmpq_mat_randtest(AQ, state, 10); ca_mat_set_fmpq_mat(A, AQ, ctx); rankq = fmpq_mat_rref(RQ, AQ); if (n_randint(state, 2)) { ca_mat_set(R, A, ctx); success = ca_mat_rref_fflu(&rank, R, R, ctx); } else { success = ca_mat_rref_fflu(&rank, R, A, ctx); } if (success) { ca_mat_set_fmpq_mat(R2, RQ, ctx); if (rank != rankq || ca_mat_check_equal(R, R2, ctx) == T_FALSE) { flint_printf("FAIL:\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("R: "); ca_mat_print(R, ctx); flint_printf("\n"); flint_printf("R2: "); ca_mat_print(R2, ctx); flint_printf("\n"); flint_printf("rank = %wd, %wd\n\n", rank, rankq); flint_abort(); } } ca_mat_clear(A, ctx); ca_mat_clear(R, ctx); ca_mat_clear(R2, ctx); fmpq_mat_clear(AQ); fmpq_mat_clear(RQ); ca_ctx_clear(ctx); } for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B, R, R2; slong rank1, rank2, r, c; int success; ca_ctx_init(ctx); r = n_randint(state, 6); c = n_randint(state, 6); ca_mat_init(A, r, c, ctx); ca_mat_init(B, r, c, ctx); ca_mat_init(R, r, c, ctx); ca_mat_init(R2, r, c, ctx); ca_mat_randtest(A, state, 1, 5, ctx); ca_mat_set(B, A, ctx); ca_mat_randrowops(B, state, 1 + n_randint(state, 20), ctx); success = ca_mat_rref_fflu(&rank1, R, A, ctx); if (success) { success = ca_mat_rref_fflu(&rank2, R2, B, ctx); if (success) { if (rank1 != rank2 || ca_mat_check_equal(R, R2, ctx) == T_FALSE) { flint_printf("FAIL:\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B: "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("R: "); ca_mat_print(R, ctx); flint_printf("\n"); flint_printf("R2: "); ca_mat_print(R2, ctx); flint_printf("\n"); flint_printf("rank = %wd, %wd\n\n", rank1, rank2); flint_abort(); } } } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(R, ctx); ca_mat_clear(R2, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-rref_lu.c000066400000000000000000000105201407704557200174100ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_randrowops(ca_mat_t mat, flint_rand_t state, slong count, ca_ctx_t ctx) { slong c, i, j, k; slong m = mat->r; slong n = mat->c; if (mat->r == 0 || mat->c == 0) return; for (c = 0; c < count; c++) { if ((i = n_randint(state, m)) == (j = n_randint(state, m))) continue; if (n_randint(state, 2)) for (k = 0; k < n; k++) ca_add(ca_mat_entry(mat, j, k), ca_mat_entry(mat, j, k), ca_mat_entry(mat, i, k), ctx); else for (k = 0; k < n; k++) ca_sub(ca_mat_entry(mat, j, k), ca_mat_entry(mat, j, k), ca_mat_entry(mat, i, k), ctx); } } int main() { slong iter; flint_rand_t state; flint_printf("rref_lu..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, R, R2; fmpq_mat_t AQ, RQ; slong rank, rankq, r, c; int success; ca_ctx_init(ctx); r = n_randint(state, 10); c = n_randint(state, 10); ca_mat_init(A, r, c, ctx); ca_mat_init(R, r, c, ctx); ca_mat_init(R2, r, c, ctx); fmpq_mat_init(AQ, r, c); fmpq_mat_init(RQ, r, c); fmpq_mat_randtest(AQ, state, 10); ca_mat_set_fmpq_mat(A, AQ, ctx); rankq = fmpq_mat_rref(RQ, AQ); if (n_randint(state, 2)) { ca_mat_set(R, A, ctx); success = ca_mat_rref_lu(&rank, R, R, ctx); } else { success = ca_mat_rref_lu(&rank, R, A, ctx); } if (success) { ca_mat_set_fmpq_mat(R2, RQ, ctx); if (rank != rankq || ca_mat_check_equal(R, R2, ctx) == T_FALSE) { flint_printf("FAIL:\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("R: "); ca_mat_print(R, ctx); flint_printf("\n"); flint_printf("R2: "); ca_mat_print(R2, ctx); flint_printf("\n"); flint_printf("rank = %wd, %wd\n\n", rank, rankq); flint_abort(); } } ca_mat_clear(A, ctx); ca_mat_clear(R, ctx); ca_mat_clear(R2, ctx); fmpq_mat_clear(AQ); fmpq_mat_clear(RQ); ca_ctx_clear(ctx); } for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, B, R, R2; slong rank1, rank2, r, c; int success; ca_ctx_init(ctx); r = n_randint(state, 6); c = n_randint(state, 6); ca_mat_init(A, r, c, ctx); ca_mat_init(B, r, c, ctx); ca_mat_init(R, r, c, ctx); ca_mat_init(R2, r, c, ctx); ca_mat_randtest(A, state, 1, 5, ctx); ca_mat_set(B, A, ctx); ca_mat_randrowops(B, state, 1 + n_randint(state, 20), ctx); success = ca_mat_rref_lu(&rank1, R, A, ctx); if (success) { success = ca_mat_rref_lu(&rank2, R2, B, ctx); if (success) { if (rank1 != rank2 || ca_mat_check_equal(R, R2, ctx) == T_FALSE) { flint_printf("FAIL:\n"); flint_printf("A: "); ca_mat_print(A, ctx); flint_printf("\n"); flint_printf("B: "); ca_mat_print(B, ctx); flint_printf("\n"); flint_printf("R: "); ca_mat_print(R, ctx); flint_printf("\n"); flint_printf("R2: "); ca_mat_print(R2, ctx); flint_printf("\n"); flint_printf("rank = %wd, %wd\n\n", rank1, rank2); flint_abort(); } } } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(R, ctx); ca_mat_clear(R2, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-solve_tril.c000066400000000000000000000054111407704557200201370ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("solve_tril..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, X, B, Y; slong rows, cols, i, j; int unit; rows = n_randint(state, 15); cols = n_randint(state, 15); unit = n_randint(state, 2); ca_ctx_init(ctx); ca_mat_init(A, rows, rows, ctx); ca_mat_init(B, rows, cols, ctx); ca_mat_init(X, rows, cols, ctx); ca_mat_init(Y, rows, cols, ctx); /* todo: test number fields, etc. */ ca_mat_randtest_rational(A, state, 5, ctx); ca_mat_randtest_rational(X, state, 5, ctx); ca_mat_randtest_rational(Y, state, 5, ctx); for (i = 0; i < rows; i++) { if (unit) ca_one(ca_mat_entry(A, i, i), ctx); else ca_set_ui(ca_mat_entry(A, i, i), 1 + n_randint(state, 100), ctx); for (j = i + 1; j < rows; j++) ca_zero(ca_mat_entry(A, i, j), ctx); } ca_mat_mul(B, A, X, ctx); if (unit) /* check that diagonal entries are ignored */ { for (i = 0; i < rows; i++) ca_set_ui(ca_mat_entry(A, i, i), 1 + n_randint(state, 100), ctx); } /* Check Y = A^(-1) * (A * X) = X */ /* Check Y = A^(-1) * (A * X) = X */ if (n_randint(state, 2)) { ca_mat_solve_tril(Y, A, B, unit, ctx); } else { ca_mat_set(Y, B, ctx); ca_mat_solve_tril(Y, A, Y, unit, ctx); } if (ca_mat_check_equal(Y, X, ctx) == T_FALSE) { flint_printf("FAIL\n"); flint_printf("A = \n"); ca_mat_print(A, ctx); flint_printf("\n\n"); flint_printf("B = \n"); ca_mat_print(B, ctx); flint_printf("\n\n"); flint_printf("X = \n"); ca_mat_print(X, ctx); flint_printf("\n\n"); flint_printf("Y = \n"); ca_mat_print(Y, ctx); flint_printf("\n\n"); flint_abort(); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(X, ctx); ca_mat_clear(Y, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/test/t-solve_triu.c000066400000000000000000000053261407704557200201550ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" int main() { slong iter; flint_rand_t state; flint_printf("solve_triu...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_mat_t A, X, B, Y; slong rows, cols, i, j; int unit; rows = n_randint(state, 15); cols = n_randint(state, 15); unit = n_randint(state, 2); ca_ctx_init(ctx); ca_mat_init(A, rows, rows, ctx); ca_mat_init(B, rows, cols, ctx); ca_mat_init(X, rows, cols, ctx); ca_mat_init(Y, rows, cols, ctx); /* todo: test number fields, etc. */ ca_mat_randtest_rational(A, state, 5, ctx); ca_mat_randtest_rational(X, state, 5, ctx); ca_mat_randtest_rational(Y, state, 5, ctx); for (i = 0; i < rows; i++) { if (unit) ca_one(ca_mat_entry(A, i, i), ctx); else ca_set_ui(ca_mat_entry(A, i, i), 1 + n_randint(state, 100), ctx); for (j = 0; j < i; j++) ca_zero(ca_mat_entry(A, i, j), ctx); } ca_mat_mul(B, A, X, ctx); if (unit) /* check that diagonal entries are ignored */ { for (i = 0; i < rows; i++) ca_set_ui(ca_mat_entry(A, i, i), 1 + n_randint(state, 100), ctx); } /* Check Y = A^(-1) * (A * X) = X */ if (n_randint(state, 2)) { ca_mat_solve_triu(Y, A, B, unit, ctx); } else { ca_mat_set(Y, B, ctx); ca_mat_solve_triu(Y, A, Y, unit, ctx); } if (ca_mat_check_equal(Y, X, ctx) == T_FALSE) { flint_printf("FAIL\n"); flint_printf("A = \n"); ca_mat_print(A, ctx); flint_printf("\n\n"); flint_printf("B = \n"); ca_mat_print(B, ctx); flint_printf("\n\n"); flint_printf("X = \n"); ca_mat_print(X, ctx); flint_printf("\n\n"); flint_printf("Y = \n"); ca_mat_print(Y, ctx); flint_printf("\n\n"); flint_abort(); } ca_mat_clear(A, ctx); ca_mat_clear(B, ctx); ca_mat_clear(X, ctx); ca_mat_clear(Y, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_mat/trace.c000066400000000000000000000015631407704557200156370ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_trace(ca_t trace, const ca_mat_t mat, ca_ctx_t ctx) { slong i; if (!ca_mat_is_square(mat)) { flint_printf("ca_mat_trace: a square matrix is required!\n"); flint_abort(); } if (ca_mat_is_empty(mat)) { ca_zero(trace, ctx); return; } ca_set(trace, ca_mat_entry(mat, 0, 0), ctx); for (i = 1; i < ca_mat_nrows(mat); i++) { ca_add(trace, trace, ca_mat_entry(mat, i, i), ctx); } } calcium-0.4.1/ca_mat/transfer.c000066400000000000000000000014621407704557200163630ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_transfer(ca_mat_t res, ca_ctx_t res_ctx, const ca_mat_t src, ca_ctx_t src_ctx) { slong i, j; if (res_ctx == src_ctx) { ca_mat_set(res, src, res_ctx); } else { for (i = 0; i < ca_mat_nrows(src); i++) for (j = 0; j < ca_mat_ncols(src); j++) ca_transfer(ca_mat_entry(res, i, j), res_ctx, ca_mat_entry(src, i, j), src_ctx); } } calcium-0.4.1/ca_mat/transpose.c000066400000000000000000000023571407704557200165610ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_transpose(ca_mat_t B, const ca_mat_t A, ca_ctx_t ctx) { slong i, j; if (ca_mat_nrows(B) != ca_mat_ncols(A) || ca_mat_ncols(B) != ca_mat_nrows(A)) { flint_printf("Exception (ca_mat_transpose). Incompatible dimensions.\n"); flint_abort(); } if (ca_mat_is_empty(A)) return; if (A == B) /* In-place, guaranteed to be square */ { for (i = 0; i < ca_mat_nrows(A) - 1; i++) { for (j = i + 1; j < ca_mat_ncols(A); j++) { ca_swap(ca_mat_entry(A, i, j), ca_mat_entry(A, j, i), ctx); } } } else /* Not aliased; general case */ { for (i = 0; i < ca_mat_nrows(B); i++) for (j = 0; j < ca_mat_ncols(B); j++) ca_set(ca_mat_entry(B, i, j), ca_mat_entry(A, j, i), ctx); } } calcium-0.4.1/ca_mat/window_init.c000066400000000000000000000014031407704557200170640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_window_init(ca_mat_t window, const ca_mat_t mat, slong r1, slong c1, slong r2, slong c2, ca_ctx_t ctx) { slong i; window->entries = NULL; window->rows = flint_malloc((r2 - r1) * sizeof(ca_ptr)); for (i = 0; i < r2 - r1; i++) window->rows[i] = mat->rows[r1 + i] + c1; window->r = r2 - r1; window->c = c2 - c1; } calcium-0.4.1/ca_mat/zero.c000066400000000000000000000011521407704557200155120ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_mat.h" void ca_mat_zero(ca_mat_t mat, ca_ctx_t ctx) { slong i, j; for (i = 0; i < ca_mat_nrows(mat); i++) for (j = 0; j < ca_mat_ncols(mat); j++) ca_zero(ca_mat_entry(mat, i, j), ctx); } calcium-0.4.1/ca_poly.h000066400000000000000000000253371407704557200147550ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef CA_POLY_H #define CA_POLY_H #ifdef CA_POLY_INLINES_C #define CA_POLY_INLINE #else #define CA_POLY_INLINE static __inline__ #endif #include #include "flint/flint.h" #include "flint/fmpz_poly.h" #include "flint/fmpq_poly.h" #include "arb_poly.h" #include "acb_poly.h" #include "antic/nf.h" #include "antic/nf_elem.h" #include "ca.h" #include "ca_vec.h" #ifdef __cplusplus extern "C" { #endif /* Polynomial object */ typedef struct { ca_struct * coeffs; slong length; slong alloc; } ca_poly_struct; typedef ca_poly_struct ca_poly_t[1]; /* todo: return NULL when out of bounds? */ CA_POLY_INLINE ca_ptr ca_poly_coeff_ptr(ca_poly_t poly, slong i) { return poly->coeffs + i; } /* Vectors of polynomials */ typedef struct { ca_poly_struct * entries; slong length; slong alloc; } ca_poly_vec_struct; typedef ca_poly_vec_struct ca_poly_vec_t[1]; /* Memory management */ void ca_poly_init(ca_poly_t poly, ca_ctx_t ctx); void ca_poly_init2(ca_poly_t poly, slong len, ca_ctx_t ctx); void ca_poly_clear(ca_poly_t poly, ca_ctx_t ctx); void ca_poly_fit_length(ca_poly_t poly, slong len, ca_ctx_t ctx); void _ca_poly_set_length(ca_poly_t poly, slong len, ca_ctx_t ctx); void _ca_poly_normalise(ca_poly_t poly, ca_ctx_t ctx); CA_POLY_INLINE void ca_poly_swap(ca_poly_t poly1, ca_poly_t poly2, ca_ctx_t ctx) { ca_poly_struct t = *poly1; *poly1 = *poly2; *poly2 = t; } /* Assignment and simple values */ void ca_poly_set_ca(ca_poly_t poly, const ca_t x, ca_ctx_t ctx); void ca_poly_set_si(ca_poly_t poly, slong x, ca_ctx_t ctx); CA_POLY_INLINE void ca_poly_zero(ca_poly_t poly, ca_ctx_t ctx) { _ca_poly_set_length(poly, 0, ctx); } CA_POLY_INLINE void ca_poly_x(ca_poly_t poly, ca_ctx_t ctx) { ca_poly_fit_length(poly, 2, ctx); ca_zero(poly->coeffs, ctx); ca_one(poly->coeffs + 1, ctx); _ca_poly_set_length(poly, 2, ctx); } CA_POLY_INLINE void ca_poly_one(ca_poly_t poly, ca_ctx_t ctx) { ca_poly_set_si(poly, 1, ctx); } void ca_poly_set(ca_poly_t res, const ca_poly_t src, ca_ctx_t ctx); void ca_poly_set_fmpz_poly(ca_poly_t res, const fmpz_poly_t src, ca_ctx_t ctx); void ca_poly_set_fmpq_poly(ca_poly_t res, const fmpq_poly_t src, ca_ctx_t ctx); void ca_poly_transfer(ca_poly_t res, ca_ctx_t res_ctx, const ca_poly_t src, ca_ctx_t src_ctx); void ca_poly_set_coeff_ca(ca_poly_t poly, slong n, const ca_t x, ca_ctx_t ctx); /* Random generation */ void ca_poly_randtest(ca_poly_t poly, flint_rand_t state, slong len, slong depth, slong bits, ca_ctx_t ctx); void ca_poly_randtest_rational(ca_poly_t poly, flint_rand_t state, slong len, slong bits, ca_ctx_t ctx); /* Input and output */ void ca_poly_print(const ca_poly_t poly, ca_ctx_t ctx); void ca_poly_printn(const ca_poly_t poly, slong digits, ca_ctx_t ctx); /* Degree and leading coefficient */ int ca_poly_is_proper(const ca_poly_t poly, ca_ctx_t ctx); int ca_poly_make_monic(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx); void _ca_poly_reverse(ca_ptr res, ca_srcptr poly, slong len, slong n, ca_ctx_t ctx); void ca_poly_reverse(ca_poly_t res, const ca_poly_t poly, slong n, ca_ctx_t ctx); /* Comparisons */ truth_t _ca_poly_check_equal(ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx); truth_t ca_poly_check_equal(const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx); truth_t ca_poly_check_is_zero(const ca_poly_t poly, ca_ctx_t ctx); truth_t ca_poly_check_is_one(const ca_poly_t poly, ca_ctx_t ctx); /* Arithmetic */ void _ca_poly_shift_left(ca_ptr res, ca_srcptr poly, slong len, slong n, ca_ctx_t ctx); void ca_poly_shift_left(ca_poly_t res, const ca_poly_t poly, slong n, ca_ctx_t ctx); void _ca_poly_shift_right(ca_ptr res, ca_srcptr poly, slong len, slong n, ca_ctx_t ctx); void ca_poly_shift_right(ca_poly_t res, const ca_poly_t poly, slong n, ca_ctx_t ctx); void ca_poly_neg(ca_poly_t res, const ca_poly_t src, ca_ctx_t ctx); void _ca_poly_add(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx); void ca_poly_add(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx); void _ca_poly_sub(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx); void ca_poly_sub(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx); void _ca_poly_mul(ca_ptr C, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, ca_ctx_t ctx); void ca_poly_mul(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx); CA_POLY_INLINE void ca_poly_mul_ca(ca_poly_t res, const ca_poly_t poly, const ca_t c, ca_ctx_t ctx) { ca_poly_fit_length(res, poly->length, ctx); _ca_vec_scalar_mul_ca(res->coeffs, poly->coeffs, poly->length, c, ctx); _ca_poly_set_length(res, poly->length, ctx); _ca_poly_normalise(res, ctx); } CA_POLY_INLINE void ca_poly_div_ca(ca_poly_t res, const ca_poly_t poly, const ca_t c, ca_ctx_t ctx) { ca_poly_fit_length(res, poly->length, ctx); _ca_vec_scalar_div_ca(res->coeffs, poly->coeffs, poly->length, c, ctx); _ca_poly_set_length(res, poly->length, ctx); _ca_poly_normalise(res, ctx); } /* todo: improve, document */ CA_POLY_INLINE void ca_poly_div_fmpz(ca_poly_t res, const ca_poly_t poly, const fmpz_t c, ca_ctx_t ctx) { ca_t t; ca_init(t, ctx); ca_set_fmpz(t, c, ctx); ca_poly_div_ca(res, res, t, ctx); ca_clear(t, ctx); } void _ca_poly_mullow_same_nf(ca_ptr C, ca_srcptr A, slong Alen, ca_srcptr B, slong Blen, slong len, ca_field_t K, ca_ctx_t ctx); void _ca_poly_mullow(ca_ptr C, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, slong n, ca_ctx_t ctx); void ca_poly_mullow(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, slong n, ca_ctx_t ctx); void _ca_poly_divrem_basecase(ca_ptr Q, ca_ptr R, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, const ca_t invB, ca_ctx_t ctx); int ca_poly_divrem_basecase(ca_poly_t Q, ca_poly_t R, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx); void _ca_poly_divrem(ca_ptr Q, ca_ptr R, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, const ca_t invB, ca_ctx_t ctx); int ca_poly_divrem(ca_poly_t Q, ca_poly_t R, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx); int ca_poly_div(ca_poly_t Q, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx); int ca_poly_rem(ca_poly_t R, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx); void _ca_poly_pow_ui_trunc(ca_ptr res, ca_srcptr f, slong flen, ulong exp, slong len, ca_ctx_t ctx); void ca_poly_pow_ui_trunc(ca_poly_t res, const ca_poly_t poly, ulong exp, slong len, ca_ctx_t ctx); void _ca_poly_pow_ui(ca_ptr res, ca_srcptr f, slong flen, ulong exp, ca_ctx_t ctx); void ca_poly_pow_ui(ca_poly_t res, const ca_poly_t poly, ulong exp, ca_ctx_t ctx); /* Evaluation and composition */ void _ca_poly_evaluate_horner(ca_t res, ca_srcptr f, slong len, const ca_t x, ca_ctx_t ctx); void ca_poly_evaluate_horner(ca_t res, const ca_poly_t f, const ca_t a, ca_ctx_t ctx); void _ca_poly_evaluate(ca_t res, ca_srcptr f, slong len, const ca_t x, ca_ctx_t ctx); void ca_poly_evaluate(ca_t res, const ca_poly_t f, const ca_t a, ca_ctx_t ctx); void _ca_poly_compose_horner(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx); void ca_poly_compose_horner(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx); void _ca_poly_compose_divconquer(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx); void ca_poly_compose_divconquer(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx); void _ca_poly_compose(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx); void ca_poly_compose(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx); /* Integral and derivative */ void _ca_poly_derivative(ca_ptr res, ca_srcptr poly, slong len, ca_ctx_t ctx); void ca_poly_derivative(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx); void _ca_poly_integral(ca_ptr res, ca_srcptr poly, slong len, ca_ctx_t ctx); void ca_poly_integral(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx); /* Greatest common divisor */ slong _ca_poly_gcd_euclidean(ca_ptr G, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, ca_ctx_t ctx); int ca_poly_gcd_euclidean(ca_poly_t G, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx); slong _ca_poly_gcd(ca_ptr G, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, ca_ctx_t ctx); int ca_poly_gcd(ca_poly_t G, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx); /* Power series division */ void _ca_poly_inv_series(ca_ptr res, ca_srcptr f, slong flen, slong len, ca_ctx_t ctx); void ca_poly_inv_series(ca_poly_t res, const ca_poly_t f, slong len, ca_ctx_t ctx); void _ca_poly_div_series(ca_ptr res, ca_srcptr f, slong flen, ca_srcptr g, slong glen, slong len, ca_ctx_t ctx); void ca_poly_div_series(ca_poly_t res, const ca_poly_t f, const ca_poly_t g, slong len, ca_ctx_t ctx); /* Elementary functions */ void _ca_poly_exp_series(ca_ptr res, ca_srcptr f, slong flen, slong len, ca_ctx_t ctx); void ca_poly_exp_series(ca_poly_t res, const ca_poly_t f, slong len, ca_ctx_t ctx); void _ca_poly_log_series(ca_ptr res, ca_srcptr f, slong flen, slong len, ca_ctx_t ctx); void ca_poly_log_series(ca_poly_t res, const ca_poly_t f, slong len, ca_ctx_t ctx); void _ca_poly_atan_series(ca_ptr res, ca_srcptr f, slong flen, slong len, ca_ctx_t ctx); void ca_poly_atan_series(ca_poly_t res, const ca_poly_t f, slong len, ca_ctx_t ctx); /* Vectors of polynomials */ ca_poly_struct * _ca_poly_vec_init(slong len, ca_ctx_t ctx); void ca_poly_vec_init(ca_poly_vec_t res, slong len, ca_ctx_t ctx); void _ca_poly_vec_fit_length(ca_poly_vec_t vec, slong len, ca_ctx_t ctx); void ca_poly_vec_set_length(ca_poly_vec_t vec, slong len, ca_ctx_t ctx); void _ca_poly_vec_clear(ca_poly_struct * v, slong len, ca_ctx_t ctx); void ca_poly_vec_clear(ca_poly_vec_t vec, ca_ctx_t ctx); void ca_poly_vec_append(ca_poly_vec_t vec, const ca_poly_t f, ca_ctx_t ctx); /* Roots and factorization */ int ca_poly_factor_squarefree(ca_t c, ca_poly_vec_t fac, ulong * exp, const ca_poly_t F, ca_ctx_t ctx); int ca_poly_squarefree_part(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx); void _ca_poly_set_roots(ca_ptr poly, ca_srcptr roots, const ulong * exp, slong len, ca_ctx_t ctx); void ca_poly_set_roots(ca_poly_t poly, ca_vec_t roots, const ulong * exp, ca_ctx_t ctx); int _ca_poly_roots(ca_ptr roots, ca_srcptr poly, slong len, ca_ctx_t ctx); int ca_poly_roots(ca_vec_t roots, ulong * exp, const ca_poly_t poly, ca_ctx_t ctx); #ifdef __cplusplus } #endif #endif calcium-0.4.1/ca_poly/000077500000000000000000000000001407704557200145725ustar00rootroot00000000000000calcium-0.4.1/ca_poly/add.c000066400000000000000000000022521407704557200154670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_add(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) { slong i, min = FLINT_MIN(len1, len2); for (i = 0; i < min; i++) ca_add(res + i, poly1 + i, poly2 + i, ctx); for (i = min; i < len1; i++) ca_set(res + i, poly1 + i, ctx); for (i = min; i < len2; i++) ca_set(res + i, poly2 + i, ctx); } void ca_poly_add(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) { slong max = FLINT_MAX(poly1->length, poly2->length); ca_poly_fit_length(res, max, ctx); _ca_poly_add(res->coeffs, poly1->coeffs, poly1->length, poly2->coeffs, poly2->length, ctx); _ca_poly_set_length(res, max, ctx); _ca_poly_normalise(res, ctx); } calcium-0.4.1/ca_poly/atan_series.c000066400000000000000000000040561407704557200172400ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_atan_series(ca_ptr res, ca_srcptr f, slong flen, slong len, ca_ctx_t ctx) { ca_t c; flen = FLINT_MIN(flen, len); if (CA_IS_SPECIAL(f)) { if (ca_is_unknown(f, ctx)) _ca_vec_unknown(res, len, ctx); else _ca_vec_undefined(res, len, ctx); return; } ca_init(c, ctx); ca_atan(c, f, ctx); if (flen == 1) { _ca_vec_zero(res + 1, len - 1, ctx); } else { ca_ptr t, u; slong ulen; t = _ca_vec_init(len, ctx); u = _ca_vec_init(len, ctx); /* atan(h(x)) = integral(h'(x)/(1+h(x)^2)) */ ulen = FLINT_MIN(len, 2 * flen - 1); _ca_poly_mullow(u, f, flen, f, flen, ulen, ctx); ca_add_ui(u, u, 1, ctx); _ca_poly_derivative(t, f, flen, ctx); _ca_poly_div_series(res, t, flen - 1, u, ulen, len, ctx); _ca_poly_integral(res, res, len, ctx); _ca_vec_clear(t, len, ctx); _ca_vec_clear(u, len, ctx); } ca_swap(res, c, ctx); if (ca_check_is_number(res, ctx) != T_TRUE) { if (ca_is_unknown(res, ctx)) _ca_vec_unknown(res + 1, len - 1, ctx); else _ca_vec_undefined(res + 1, len - 1, ctx); return; } ca_clear(c, ctx); } void ca_poly_atan_series(ca_poly_t res, const ca_poly_t f, slong len, ca_ctx_t ctx) { slong flen = f->length; if (flen == 0 || len == 0) { ca_poly_zero(res, ctx); return; } ca_poly_fit_length(res, len, ctx); _ca_poly_atan_series(res->coeffs, f->coeffs, flen, len, ctx); _ca_poly_set_length(res, len, ctx); _ca_poly_normalise(res, ctx); } calcium-0.4.1/ca_poly/check_equal.c000066400000000000000000000025341407704557200172060ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" truth_t _ca_poly_check_equal(ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) { truth_t eq, res; slong i; res = T_TRUE; for (i = 0; i < len2; i++) { eq = ca_check_equal(poly1 + i, poly2 + i, ctx); if (eq == T_FALSE) return T_FALSE; if (eq == T_UNKNOWN) res = T_UNKNOWN; } for (i = len2; i < len1; i++) { eq = ca_check_is_zero(poly1 + i, ctx); if (eq == T_FALSE) return T_FALSE; if (eq == T_UNKNOWN) res = T_UNKNOWN; } return res; } truth_t ca_poly_check_equal(const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) { slong len1 = poly1->length; slong len2 = poly2->length; if (len1 >= len2) return _ca_poly_check_equal(poly1->coeffs, len1, poly2->coeffs, len2, ctx); else return _ca_poly_check_equal(poly2->coeffs, len2, poly1->coeffs, len1, ctx); } calcium-0.4.1/ca_poly/check_is_one.c000066400000000000000000000013071407704557200173500ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" truth_t ca_poly_check_is_one(const ca_poly_t poly, ca_ctx_t ctx) { ca_t t; truth_t res; if (poly->length == 0) return T_FALSE; ca_init(t, ctx); ca_one(t, ctx); res = _ca_poly_check_equal(poly->coeffs, poly->length, t, 1, ctx); ca_clear(t, ctx); return res; } calcium-0.4.1/ca_poly/check_is_zero.c000066400000000000000000000012631407704557200175470ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" truth_t ca_poly_check_is_zero(const ca_poly_t poly, ca_ctx_t ctx) { ca_t t; truth_t res; if (poly->length == 0) return T_TRUE; ca_init(t, ctx); res = _ca_poly_check_equal(poly->coeffs, poly->length, t, 1, ctx); ca_clear(t, ctx); return res; } calcium-0.4.1/ca_poly/clear.c000066400000000000000000000011131407704557200160200ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_clear(ca_poly_t poly, ca_ctx_t ctx) { slong i; for (i = 0; i < poly->alloc; i++) ca_clear(poly->coeffs + i, ctx); flint_free(poly->coeffs); } calcium-0.4.1/ca_poly/compose.c000066400000000000000000000065551407704557200164160ustar00rootroot00000000000000/* Copyright (C) 2010 William Hart Copyright (C) 2012 Sebastian Pancratz Copyright (C) 2012, 2016, 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" /* todo: implement taylor shift */ #if 0 /* compose by poly2 = a*x^n + c, no aliasing; n >= 1 */ void _ca_poly_compose_axnc(ca_ptr res, ca_srcptr poly1, slong len1, const ca_t c, const ca_t a, slong n, ca_ctx_t ctx) { slong i; _ca_vec_set(res, poly1, len1, ctx); /* shift by c (c = 0 case will be fast) */ _ca_poly_taylor_shift(res, c, len1, ctx); /* multiply by powers of a */ if (!ca_is_one(a, ctx)) { if (ca_equal_si(a, -1, ctx)) { for (i = 1; i < len1; i += 2) ca_neg(res + i, res + i, ctx); } else if (len1 == 2) { ca_mul(res + 1, res + 1, a, ctx); } else { ca_t t; ca_init(t, ctx); ca_set(t, a, ctx); for (i = 1; i < len1; i++) { ca_mul(res + i, res + i, t, ctx); if (i + 1 < len1) ca_mul(t, t, a, ctx); } ca_clear(t, ctx); } } /* stretch */ for (i = len1 - 1; i >= 1 && n > 1; i--) { ca_swap(res + i * n, res + i, ctx); _ca_vec_zero(res + (i - 1) * n + 1, n - 1, ctx); } } #endif void _ca_poly_compose(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) { if (len1 == 1) { ca_set(res, poly1, ctx); } else if (len2 == 1) { _ca_poly_evaluate(res, poly1, len1, poly2, ctx); } #if 0 else if (_ca_vec_is_zero(poly2 + 1, len2 - 2)) { _ca_poly_compose_axnc(res, poly1, len1, poly2, poly2 + len2 - 1, len2 - 1, ctx); } #endif else if (len1 <= 7) { _ca_poly_compose_horner(res, poly1, len1, poly2, len2, ctx); } else { _ca_poly_compose_divconquer(res, poly1, len1, poly2, len2, ctx); } } void ca_poly_compose(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) { const slong len1 = poly1->length; const slong len2 = poly2->length; if (len1 == 0) { ca_poly_zero(res, ctx); } else if (len1 == 1 || len2 == 0) { ca_poly_set_ca(res, poly1->coeffs, ctx); } else { const slong lenr = (len1 - 1) * (len2 - 1) + 1; if (res != poly1 && res != poly2) { ca_poly_fit_length(res, lenr, ctx); _ca_poly_compose(res->coeffs, poly1->coeffs, len1, poly2->coeffs, len2, ctx); } else { ca_poly_t t; ca_poly_init2(t, lenr, ctx); _ca_poly_compose(t->coeffs, poly1->coeffs, len1, poly2->coeffs, len2, ctx); ca_poly_swap(res, t, ctx); ca_poly_clear(t, ctx); } _ca_poly_set_length(res, lenr, ctx); _ca_poly_normalise(res, ctx); } } calcium-0.4.1/ca_poly/compose_divconquer.c000066400000000000000000000117241407704557200206470ustar00rootroot00000000000000/* Copyright (C) 2010 William Hart Copyright (C) 2012 Sebastian Pancratz Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_compose_divconquer(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) { slong i, j, k, n; slong *hlen, alloc, powlen; ca_ptr v, pow, temp; ca_ptr * h; if (len1 == 1) { ca_set(res, poly1, ctx); return; } if (len2 == 1) { _ca_poly_evaluate(res, poly1, len1, poly2, ctx); return; } if (len1 == 2) { _ca_poly_compose_horner(res, poly1, len1, poly2, len2, ctx); return; } /* Initialisation */ hlen = (slong *) flint_malloc(((len1 + 1) / 2) * sizeof(slong)); for (k = 1; (2 << k) < len1; k++) ; hlen[0] = hlen[1] = ((1 << k) - 1) * (len2 - 1) + 1; for (i = k - 1; i > 0; i--) { slong hi = (len1 + (1 << i) - 1) / (1 << i); for (n = (hi + 1) / 2; n < hi; n++) hlen[n] = ((1 << i) - 1) * (len2 - 1) + 1; } powlen = (1 << k) * (len2 - 1) + 1; alloc = 0; for (i = 0; i < (len1 + 1) / 2; i++) alloc += hlen[i]; v = _ca_vec_init(alloc + 2 * powlen, ctx); h = (ca_ptr *) flint_malloc(((len1 + 1) / 2) * sizeof(ca_ptr)); h[0] = v; for (i = 0; i < (len1 - 1) / 2; i++) { h[i + 1] = h[i] + hlen[i]; hlen[i] = 0; } hlen[(len1 - 1) / 2] = 0; pow = v + alloc; temp = pow + powlen; /* Let's start the actual work */ for (i = 0, j = 0; i < len1 / 2; i++, j += 2) { if (ca_check_is_zero(poly1 + j + 1, ctx) != T_TRUE) { _ca_vec_scalar_mul_ca(h[i], poly2, len2, poly1 + j + 1, ctx); ca_add(h[i], h[i], poly1 + j, ctx); hlen[i] = len2; } else if (ca_check_is_zero(poly1 + j, ctx) != T_TRUE) { ca_set(h[i], poly1 + j, ctx); hlen[i] = 1; } } if ((len1 & WORD(1))) { if (ca_check_is_zero(poly1 + j, ctx) != T_TRUE) { ca_set(h[i], poly1 + j, ctx); hlen[i] = 1; } } _ca_poly_mul(pow, poly2, len2, poly2, len2, ctx); powlen = 2 * len2 - 1; for (n = (len1 + 1) / 2; n > 2; n = (n + 1) / 2) { if (hlen[1] > 0) { slong templen = powlen + hlen[1] - 1; _ca_poly_mul(temp, pow, powlen, h[1], hlen[1], ctx); _ca_poly_add(h[0], temp, templen, h[0], hlen[0], ctx); hlen[0] = FLINT_MAX(hlen[0], templen); } for (i = 1; i < n / 2; i++) { if (hlen[2*i + 1] > 0) { _ca_poly_mul(h[i], pow, powlen, h[2*i + 1], hlen[2*i + 1], ctx); hlen[i] = hlen[2*i + 1] + powlen - 1; } else hlen[i] = 0; _ca_poly_add(h[i], h[i], hlen[i], h[2*i], hlen[2*i], ctx); hlen[i] = FLINT_MAX(hlen[i], hlen[2*i]); } if ((n & WORD(1))) { _ca_vec_set(h[i], h[2*i], hlen[2*i], ctx); hlen[i] = hlen[2*i]; } _ca_poly_mul(temp, pow, powlen, pow, powlen, ctx); powlen += powlen - 1; { ca_ptr t = pow; pow = temp; temp = t; } } _ca_poly_mul(res, pow, powlen, h[1], hlen[1], ctx); _ca_vec_add(res, res, h[0], hlen[0], ctx); _ca_vec_clear(v, alloc + 2 * powlen, ctx); flint_free(h); flint_free(hlen); } void ca_poly_compose_divconquer(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) { const slong len1 = poly1->length; const slong len2 = poly2->length; if (len1 == 0) { ca_poly_zero(res, ctx); } else if (len1 == 1 || len2 == 0) { ca_poly_set_ca(res, poly1->coeffs, ctx); } else { const slong lenr = (len1 - 1) * (len2 - 1) + 1; if (res != poly1 && res != poly2) { ca_poly_fit_length(res, lenr, ctx); _ca_poly_compose_divconquer(res->coeffs, poly1->coeffs, len1, poly2->coeffs, len2, ctx); } else { ca_poly_t t; ca_poly_init2(t, lenr, ctx); _ca_poly_compose_divconquer(t->coeffs, poly1->coeffs, len1, poly2->coeffs, len2, ctx); ca_poly_swap(res, t, ctx); ca_poly_clear(t, ctx); } _ca_poly_set_length(res, lenr, ctx); _ca_poly_normalise(res, ctx); } } calcium-0.4.1/ca_poly/compose_horner.c000066400000000000000000000056001407704557200177610ustar00rootroot00000000000000/* Copyright (C) 2010 William Hart Copyright (C) 2012 Sebastian Pancratz Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_compose_horner(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) { if (len1 == 1) { ca_set(res, poly1, ctx); } else if (len2 == 1) { _ca_poly_evaluate(res, poly1, len1, poly2, ctx); } else if (len1 == 2) { _ca_vec_scalar_mul_ca(res, poly2, len2, poly1 + 1, ctx); ca_add(res, res, poly1, ctx); } else { const slong alloc = (len1 - 1) * (len2 - 1) + 1; slong i = len1 - 1, lenr = len2; ca_ptr t, t1, t2; t = _ca_vec_init(alloc, ctx); if (len1 % 2 == 0) { t1 = res; t2 = t; } else { t1 = t; t2 = res; } /* Perform the first two steps as one, "res = a(m) * poly2 + a(m-1)". */ { _ca_vec_scalar_mul_ca(t1, poly2, len2, poly1 + i, ctx); i--; ca_add(t1 + 0, t1 + 0, poly1 + i, ctx); } while (i--) { _ca_poly_mul(t2, t1, lenr, poly2, len2, ctx); lenr += len2 - 1; { void *t_ = t1; t1 = t2; t2 = t_; } ca_add(t1 + 0, t1 + 0, poly1 + i, ctx); } _ca_vec_clear(t, alloc, ctx); } } void ca_poly_compose_horner(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) { const slong len1 = poly1->length; const slong len2 = poly2->length; if (len1 == 0) { ca_poly_zero(res, ctx); } else if (len1 == 1 || len2 == 0) { ca_poly_set_ca(res, poly1->coeffs, ctx); } else { const slong lenr = (len1 - 1) * (len2 - 1) + 1; if (res != poly1 && res != poly2) { ca_poly_fit_length(res, lenr, ctx); _ca_poly_compose_horner(res->coeffs, poly1->coeffs, len1, poly2->coeffs, len2, ctx); } else { ca_poly_t t; ca_poly_init2(t, lenr, ctx); _ca_poly_compose_horner(t->coeffs, poly1->coeffs, len1, poly2->coeffs, len2, ctx); ca_poly_swap(res, t, ctx); ca_poly_clear(t, ctx); } _ca_poly_set_length(res, lenr, ctx); _ca_poly_normalise(res, ctx); } } calcium-0.4.1/ca_poly/derivative.c000066400000000000000000000016561407704557200171100ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_derivative(ca_ptr res, ca_srcptr poly, slong len, ca_ctx_t ctx) { slong i; for (i = 1; i < len; i++) ca_mul_ui(res + (i - 1), poly + i, i, ctx); } void ca_poly_derivative(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx) { slong len = poly->length; if (len < 2) { ca_poly_zero(res, ctx); } else { ca_poly_fit_length(res, len - 1, ctx); _ca_poly_derivative(res->coeffs, poly->coeffs, len, ctx); _ca_poly_set_length(res, len - 1, ctx); } } calcium-0.4.1/ca_poly/div_series.c000066400000000000000000000105021407704557200170700ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" ca_field_ptr _ca_vec_same_field2(ca_srcptr A, slong Alen, ca_srcptr B, slong Blen, ca_ctx_t ctx); void _ca_poly_div_series(ca_ptr Q, ca_srcptr A, slong Alen, ca_srcptr B, slong Blen, slong len, ca_ctx_t ctx) { Alen = FLINT_MIN(Alen, len); Blen = FLINT_MIN(Blen, len); if (CA_IS_SPECIAL(A) || CA_IS_SPECIAL(B)) { if (ca_is_unknown(A, ctx) || ca_is_unknown(B, ctx)) _ca_vec_unknown(Q, len, ctx); else _ca_vec_undefined(Q, len, ctx); return; } /* todo: tuning */ /* todo: shallow copy with integers */ if (Blen >= 4 && _ca_vec_is_fmpq_vec(A, Alen, ctx) && _ca_vec_is_fmpq_vec(B, Blen, ctx) && !fmpq_is_zero(CA_FMPQ(B))) { fmpz *p, *r, *s; fmpz_t pden, rden, sden; p = _fmpz_vec_init(Alen); r = _fmpz_vec_init(Blen); s = _fmpz_vec_init(len); fmpz_init(pden); fmpz_init(rden); fmpz_init(sden); _ca_vec_fmpq_vec_get_fmpz_vec_den(p, pden, A, Alen, ctx); _ca_vec_fmpq_vec_get_fmpz_vec_den(r, rden, B, Blen, ctx); _fmpq_poly_div_series(s, sden, p, pden, Alen, r, rden, Blen, len); _ca_vec_set_fmpz_vec_div_fmpz(Q, s, sden, len, ctx); fmpz_clear(pden); fmpz_clear(rden); fmpz_clear(sden); _fmpz_vec_clear(p, Alen); _fmpz_vec_clear(r, Blen); _fmpz_vec_clear(s, len); return; } if (Blen == 1) { _ca_vec_scalar_div_ca(Q, A, Alen, B, ctx); _ca_vec_zero(Q + Alen, len - Alen, ctx); } else { int is_one; ca_field_ptr K; ca_t q; slong i; if (Blen > 8) { K = _ca_vec_same_field2(A, Alen, B, Blen, ctx); /* If we have fast multiplication and inversion */ /* Todo: also want this if inversion alone is fast and Alen is small */ if (K != NULL && CA_FIELD_IS_NF(K)) { if (len > 2 * qqbar_degree(CA_FIELD_NF_QQBAR(K))) { ca_ptr Binv; Binv = _ca_vec_init(len, ctx); _ca_poly_inv_series(Binv, B, Blen, len, ctx); _ca_poly_mullow(Q, Binv, len, A, Alen, len, ctx); _ca_vec_clear(Binv, len, ctx); return; } } } ca_init(q, ctx); ca_inv(q, B + 0, ctx); ca_mul(Q, A + 0, q, ctx); is_one = (ca_check_is_one(q, ctx) == T_TRUE); for (i = 1; i < len; i++) { ca_dot(Q + i, (i < Alen) ? A + i : NULL, 1, B + 1, 1, Q + i - 1, -1, FLINT_MIN(i, Blen - 1), ctx); if (!is_one) ca_mul(Q + i, Q + i, q, ctx); } ca_clear(q, ctx); } } void ca_poly_div_series(ca_poly_t Q, const ca_poly_t A, const ca_poly_t B, slong len, ca_ctx_t ctx) { if (len == 0) { ca_poly_zero(Q, ctx); return; } if (B->length == 0) { ca_poly_fit_length(Q, len, ctx); ca_unknown(Q->coeffs, ctx); /* todo: uinf when A != 0? */ _ca_vec_undefined(Q->coeffs + 1, len - 1, ctx); _ca_poly_set_length(Q, len, ctx); return; } if (A->length == 0) { if (ca_check_is_zero(B->coeffs, ctx) == T_FALSE) { ca_poly_zero(Q, ctx); } else { ca_poly_fit_length(Q, len, ctx); _ca_vec_unknown(Q->coeffs, len, ctx); _ca_poly_set_length(Q, len, ctx); } return; } if (Q == A || Q == B) { ca_poly_t t; ca_poly_init(t, ctx); ca_poly_div_series(t, A, B, len, ctx); ca_poly_swap(Q, t, ctx); ca_poly_clear(t, ctx); return; } ca_poly_fit_length(Q, len, ctx); _ca_poly_div_series(Q->coeffs, A->coeffs, A->length, B->coeffs, B->length, len, ctx); _ca_poly_set_length(Q, len, ctx); _ca_poly_normalise(Q, ctx); } calcium-0.4.1/ca_poly/divrem.c000066400000000000000000000052321407704557200162260ustar00rootroot00000000000000/* Copyright (C) 2012 Sebastian Pancratz Copyright (C) 2013 Mike Hansen Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_divrem(ca_ptr Q, ca_ptr R, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, const ca_t invB, ca_ctx_t ctx) { _ca_poly_divrem_basecase(Q, R, A, lenA, B, lenB, invB, ctx); } int ca_poly_divrem(ca_poly_t Q, ca_poly_t R, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx) { slong lenA = A->length, lenB = B->length, lenQ = lenA - lenB + 1; ca_ptr q, r; ca_t invB; if (lenB == 0) return 0; if (lenA < lenB) { if (ca_check_is_zero(B->coeffs + lenB - 1, ctx) == T_FALSE) { ca_poly_set(R, A, ctx); ca_poly_zero(Q, ctx); return 1; } else { return 0; } } ca_init(invB, ctx); ca_inv(invB, B->coeffs + lenB - 1, ctx); if (CA_IS_SPECIAL(invB)) { ca_clear(invB, ctx); return 0; } if (Q == A || Q == B) { q = _ca_vec_init(lenQ, ctx); } else { ca_poly_fit_length(Q, lenQ, ctx); q = Q->coeffs; } if (R == B) { r = _ca_vec_init(lenA, ctx); } else { ca_poly_fit_length(R, lenA, ctx); r = R->coeffs; } _ca_poly_divrem(q, r, A->coeffs, lenA, B->coeffs, lenB, invB, ctx); if (Q == A || Q == B) { _ca_vec_clear(Q->coeffs, Q->alloc, ctx); Q->coeffs = q; Q->alloc = lenQ; Q->length = lenQ; } else { _ca_poly_set_length(Q, lenQ, ctx); } if (R == B) { _ca_vec_clear(R->coeffs, R->alloc, ctx); R->coeffs = r; R->alloc = lenA; R->length = lenA; } _ca_poly_set_length(R, lenB - 1, ctx); _ca_poly_normalise(R, ctx); ca_clear(invB, ctx); return 1; } int ca_poly_div(ca_poly_t Q, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx) { ca_poly_t R; int success; ca_poly_init(R, ctx); success = ca_poly_divrem(Q, R, A, B, ctx); ca_poly_clear(R, ctx); return success; } int ca_poly_rem(ca_poly_t R, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx) { ca_poly_t Q; int success; ca_poly_init(Q, ctx); success = ca_poly_divrem(Q, R, A, B, ctx); ca_poly_clear(Q, ctx); return success; } calcium-0.4.1/ca_poly/divrem_basecase.c000066400000000000000000000050501407704557200200520ustar00rootroot00000000000000/* Copyright (C) 2012 Sebastian Pancratz Copyright (C) 2013 Mike Hansen Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_divrem_basecase(ca_ptr Q, ca_ptr R, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, const ca_t invB, ca_ctx_t ctx) { slong iQ, iR; if (R != A) _ca_vec_set(R, A, lenA, ctx); for (iQ = lenA - lenB, iR = lenA - 1; iQ >= 0; iQ--, iR--) { if (ca_check_is_zero(R + iR, ctx) == T_TRUE) { ca_zero(Q + iQ, ctx); } else { ca_mul(Q + iQ, R + iR, invB, ctx); _ca_vec_scalar_submul_ca(R + iQ, B, lenB, Q + iQ, ctx); } } } int ca_poly_divrem_basecase(ca_poly_t Q, ca_poly_t R, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx) { slong lenA = A->length, lenB = B->length, lenQ = lenA - lenB + 1; ca_ptr q, r; ca_t invB; if (lenB == 0) return 0; if (lenA < lenB) { if (ca_check_is_zero(B->coeffs + lenB - 1, ctx) == T_FALSE) { ca_poly_set(R, A, ctx); ca_poly_zero(Q, ctx); return 1; } else { return 0; } } ca_init(invB, ctx); ca_inv(invB, B->coeffs + lenB - 1, ctx); if (CA_IS_SPECIAL(invB)) { ca_clear(invB, ctx); return 0; } if (Q == A || Q == B) { q = _ca_vec_init(lenQ, ctx); } else { ca_poly_fit_length(Q, lenQ, ctx); q = Q->coeffs; } if (R == B) { r = _ca_vec_init(lenA, ctx); } else { ca_poly_fit_length(R, lenA, ctx); r = R->coeffs; } _ca_poly_divrem_basecase(q, r, A->coeffs, lenA, B->coeffs, lenB, invB, ctx); if (Q == A || Q == B) { _ca_vec_clear(Q->coeffs, Q->alloc, ctx); Q->coeffs = q; Q->alloc = lenQ; Q->length = lenQ; } else { _ca_poly_set_length(Q, lenQ, ctx); } if (R == B) { _ca_vec_clear(R->coeffs, R->alloc, ctx); R->coeffs = r; R->alloc = lenA; R->length = lenA; } _ca_poly_set_length(R, lenB - 1, ctx); _ca_poly_normalise(R, ctx); ca_clear(invB, ctx); return 1; } calcium-0.4.1/ca_poly/evaluate.c000066400000000000000000000013171407704557200165460ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_evaluate(ca_t res, ca_srcptr f, slong len, const ca_t x, ca_ctx_t ctx) { _ca_poly_evaluate_horner(res, f, len, x, ctx); } void ca_poly_evaluate(ca_t res, const ca_poly_t f, const ca_t a, ca_ctx_t ctx) { _ca_poly_evaluate(res, f->coeffs, f->length, a, ctx); } calcium-0.4.1/ca_poly/evaluate_horner.c000066400000000000000000000024341407704557200201240ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_evaluate_horner(ca_t y, ca_srcptr f, slong len, const ca_t x, ca_ctx_t ctx) { if (len == 0) { ca_zero(y, ctx); } else if (len == 1 || ca_check_is_zero(x, ctx) == T_TRUE) { ca_set(y, f, ctx); } else if (len == 2) { ca_mul(y, x, f + 1, ctx); ca_add(y, y, f + 0, ctx); } else { slong i = len - 1; ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); ca_set(u, f + i, ctx); for (i = len - 2; i >= 0; i--) { ca_mul(t, u, x, ctx); ca_add(u, f + i, t, ctx); } ca_swap(y, u, ctx); ca_clear(t, ctx); ca_clear(u, ctx); } } void ca_poly_evaluate_horner(ca_t res, const ca_poly_t f, const ca_t a, ca_ctx_t ctx) { _ca_poly_evaluate_horner(res, f->coeffs, f->length, a, ctx); } calcium-0.4.1/ca_poly/exp_series.c000066400000000000000000000150661407704557200171140ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" #include "ca_poly.h" ca_field_ptr _ca_vec_same_field2(ca_srcptr A, slong Alen, ca_srcptr B, slong Blen, ca_ctx_t ctx); void _ca_poly_exp_series_basecase(ca_ptr f, ca_srcptr h, slong hlen, slong len, ca_ctx_t ctx) { slong k; ca_ptr a; ca_t s, e; hlen = FLINT_MIN(hlen, len); ca_init(e, ctx); ca_exp(e, h, ctx); if (_ca_vec_is_fmpq_vec(h + 1, hlen - 1, ctx)) { fmpz *p, *r; fmpz_t pden, rden; p = _fmpz_vec_init(hlen); r = _fmpz_vec_init(len); fmpz_init(pden); fmpz_init(rden); _ca_vec_fmpq_vec_get_fmpz_vec_den(p + 1, pden, h + 1, hlen - 1, ctx); _fmpq_poly_exp_series(r, rden, p, pden, hlen, len); _ca_vec_set_fmpz_vec_div_fmpz(f, r, rden, len, ctx); fmpz_clear(pden); fmpz_clear(rden); _fmpz_vec_clear(p, hlen); _fmpz_vec_clear(r, len); } else { ca_init(s, ctx); a = _ca_vec_init(hlen, ctx); for (k = 1; k < hlen; k++) ca_mul_ui(a + k, h + k, k, ctx); ca_one(f, ctx); for (k = 1; k < len; k++) { ca_dot(s, NULL, 0, a + 1, 1, f + k - 1, -1, FLINT_MIN(k, hlen - 1), ctx); ca_div_ui(f + k, s, k, ctx); } _ca_vec_clear(a, hlen, ctx); ca_clear(s, ctx); } ca_swap(f, e, ctx); _ca_vec_scalar_mul_ca(f + 1, f + 1, len - 1, f, ctx); ca_clear(e, ctx); } /* c_k x^k -> c_k x^k / (m+k) */ static void _ca_poly_integral_offset(ca_ptr res, ca_srcptr poly, slong len, slong m, ca_ctx_t ctx) { slong k; for (k = 0; k < len; k++) ca_div_ui(res + k, poly + k, m + k, ctx); } void _ca_poly_exp_series_newton(ca_ptr f, ca_ptr g, ca_srcptr h, slong hlen, slong n, ca_ctx_t ctx) { slong a[FLINT_BITS]; slong i, m, l, r, alloc; ca_ptr t, hprime; int inverse; if (!(CA_IS_QQ(h, ctx) && fmpq_is_zero(CA_FMPQ(h)))) { hlen = FLINT_MIN(hlen, n); t = _ca_vec_init(hlen + 1, ctx); ca_exp(t + hlen, h, ctx); _ca_vec_set(t + 1, h + 1, hlen - 1, ctx); _ca_poly_exp_series_newton(f, g, t, hlen, n, ctx); _ca_vec_scalar_mul_ca(f, f, n, t + hlen, ctx); if (g != NULL) _ca_vec_scalar_div_ca(g, g, n, t + hlen, ctx); _ca_vec_clear(t, hlen + 1, ctx); return; } /* If g is provided, we compute g = exp(-h), and we can use g as scratch space. Otherwise, we still need to compute exp(-h) to length (n+1)/2 for intermediate use, and we still need n coefficients of scratch space. */ alloc = n; inverse = (g != NULL); if (!inverse) g = _ca_vec_init(n, ctx); hlen = FLINT_MIN(hlen, n); t = _ca_vec_init(n, ctx); hprime = _ca_vec_init(hlen - 1, ctx); _ca_poly_derivative(hprime, h, hlen, ctx); for (i = 1; (WORD(1) << i) < n; i++); a[i = 0] = n; while (n >= 15 || i == 0) a[++i] = (n = (n + 1) / 2); /* f := exp(h) + O(x^n), g := exp(-h) + O(x^n) */ _ca_poly_exp_series_basecase(f, h, FLINT_MIN(hlen, n), n, ctx); _ca_poly_inv_series(g, f, n, n, ctx); for (i--; i >= 0; i--) { m = n; /* previous length */ n = a[i]; /* new length */ l = FLINT_MIN(hlen, n) - 1; r = FLINT_MIN(l + m - 1, n - 1); if (l >= m) _ca_poly_mullow(t, hprime, l, f, m, r, ctx); else _ca_poly_mullow(t, f, m, hprime, l, r, ctx); _ca_poly_mullow(g + m, g, n - m, t + m - 1, r + 1 - m, n - m, ctx); _ca_poly_integral_offset(g + m, g + m, n - m, m, ctx); _ca_poly_mullow(f + m, f, n - m, g + m, n - m, n - m, ctx); /* g := exp(-h) + O(x^n); not needed if we only want exp(x) */ if (i != 0 || inverse) { _ca_poly_mullow(t, f, n, g, m, n, ctx); _ca_poly_mullow(g + m, g, m, t + m, n - m, n - m, ctx); _ca_vec_neg(g + m, g + m, n - m, ctx); } } _ca_vec_clear(hprime, hlen - 1, ctx); _ca_vec_clear(t, alloc, ctx); if (!inverse) _ca_vec_clear(g, alloc, ctx); } void _ca_poly_exp_series(ca_ptr f, ca_srcptr h, slong hlen, slong len, ca_ctx_t ctx) { hlen = FLINT_MIN(hlen, len); if (CA_IS_SPECIAL(h)) { if (ca_is_unknown(h, ctx)) _ca_vec_unknown(f, len, ctx); else _ca_vec_undefined(f, len, ctx); return; } if (hlen == 1) { ca_exp(f, h, ctx); _ca_vec_zero(f + 1, len - 1, ctx); } else if (len == 2) { ca_exp(f, h, ctx); ca_mul(f + 1, f, h + 1, ctx); /* safe since hlen >= 2 */ } else if (_ca_vec_check_is_zero(h + 1, hlen - 2, ctx) == T_TRUE) /* h = a + bx^d */ { slong i, j, d = hlen - 1; ca_t t; ca_init(t, ctx); ca_set(t, h + d, ctx); ca_exp(f, h, ctx); for (i = 1, j = d; j < len; j += d, i++) { ca_mul(f + j, f + j - d, t, ctx); ca_div_ui(f + j, f + j, i, ctx); _ca_vec_zero(f + j - d + 1, hlen - 2, ctx); } _ca_vec_zero(f + j - d + 1, len - (j - d + 1), ctx); ca_clear(t, ctx); } else { if (hlen >= 8) { ca_field_ptr K; K = _ca_vec_same_field2(h + 1, hlen - 1, NULL, 0, ctx); /* Newton iteration where we have fast multiplication */ if (K != NULL && CA_FIELD_IS_NF(K)) { if (len >= qqbar_degree(CA_FIELD_NF_QQBAR(K))) { _ca_poly_exp_series_newton(f, NULL, h, hlen, len, ctx); return; } } } _ca_poly_exp_series_basecase(f, h, hlen, len, ctx); } } void ca_poly_exp_series(ca_poly_t f, const ca_poly_t h, slong len, ca_ctx_t ctx) { slong hlen = h->length; if (len == 0) { ca_poly_zero(f, ctx); return; } if (hlen == 0) { ca_poly_one(f, ctx); return; } if (hlen == 1 && ca_check_is_number(h->coeffs, ctx) == T_TRUE) len = 1; ca_poly_fit_length(f, len, ctx); _ca_poly_exp_series(f->coeffs, h->coeffs, hlen, len, ctx); _ca_poly_set_length(f, len, ctx); _ca_poly_normalise(f, ctx); } calcium-0.4.1/ca_poly/factor_squarefree.c000066400000000000000000000047611407704557200204460ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int ca_poly_factor_squarefree(ca_t c, ca_poly_vec_t fac, ulong * exp, const ca_poly_t F, ca_ctx_t ctx) { ca_poly_t f, d, t1; ca_poly_t v, w, s; slong i; int success; if (F->length == 0) { ca_zero(c, ctx); ca_poly_vec_set_length(fac, 0, ctx); return 1; } if (!ca_poly_is_proper(F, ctx)) { return 0; } ca_set(c, F->coeffs + F->length - 1, ctx); if (F->length == 1) { ca_poly_vec_set_length(fac, 0, ctx); return 1; } ca_poly_init(f, ctx); ca_poly_init(d, ctx); ca_poly_init(t1, ctx); ca_poly_init(v, ctx); ca_poly_init(w, ctx); ca_poly_init(s, ctx); success = 0; ca_poly_make_monic(f, F, ctx); ca_poly_derivative(t1, f, ctx); if (!ca_poly_gcd(d, f, t1, ctx)) goto cleanup; ca_poly_vec_set_length(fac, 0, ctx); if (d->length == 1) { ca_poly_vec_append(fac, f, ctx); exp[fac->length - 1] = 1; } else { ca_poly_div(v, f, d, ctx); ca_poly_div(w, t1, d, ctx); /* invariant: v is monic, so we don't need to check if it is proper */ for (i = 1; ; i++) { ca_poly_derivative(t1, v, ctx); ca_poly_sub(s, w, t1, ctx); if (!ca_poly_is_proper(s, ctx)) goto cleanup; if (s->length == 0) { if (v->length > 1) { ca_poly_vec_append(fac, v, ctx); exp[fac->length - 1] = i; } break; } if (!ca_poly_gcd(d, v, s, ctx)) goto cleanup; ca_poly_div(v, v, d, ctx); ca_poly_div(w, s, d, ctx); if (d->length > 1) { ca_poly_vec_append(fac, d, ctx); exp[fac->length - 1] = i; } } } success = 1; cleanup: ca_poly_clear(f, ctx); ca_poly_clear(d, ctx); ca_poly_clear(t1, ctx); ca_poly_clear(v, ctx); ca_poly_clear(w, ctx); ca_poly_clear(s, ctx); return success; } calcium-0.4.1/ca_poly/fit_length.c000066400000000000000000000014511407704557200170620ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_fit_length(ca_poly_t poly, slong len, ca_ctx_t ctx) { slong i; if (len > poly->alloc) { if (len < 2 * poly->alloc) len = 2 * poly->alloc; poly->coeffs = flint_realloc(poly->coeffs, len * sizeof(ca_struct)); for (i = poly->alloc; i < len; i++) ca_init(poly->coeffs + i, ctx); poly->alloc = len; } } calcium-0.4.1/ca_poly/gcd.c000066400000000000000000000125031407704557200154740ustar00rootroot00000000000000/* Copyright (C) 2011 William Hart Copyright (C) 2012 Andres Goens Copyright (C) 2013 Mike Hansen Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "acb_mat.h" #include "ca_poly.h" int _ca_poly_check_coprime_numerical(ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, ca_ctx_t ctx) { acb_t D; slong degA, degB, i, j; slong prec; int result; acb_ptr TA, TB; degA = lenA - 1; degB = lenB - 1; TA = _acb_vec_init(lenA); TB = _acb_vec_init(lenA); acb_init(D); prec = ctx->options[CA_OPT_LOW_PREC]; for (i = 0; i <= degA; i++) ca_get_acb(TA + i, A + i, prec, ctx); for (i = 0; i <= degB; i++) ca_get_acb(TB + i, B + i, prec, ctx); if (_acb_vec_is_real(TA, lenA) && _acb_vec_is_real(TB, lenB)) { arb_mat_t R; arb_mat_init(R, degA + degB, degA + degB); for (i = 0; i < degB; i++) { for (j = 0; j <= degA; j++) { if (i == 0) arb_swap(acb_mat_entry(R, 0, j), acb_realref(TA + j)); else arb_set(arb_mat_entry(R, i, i + j), arb_mat_entry(R, 0, j)); } } for (i = 0; i < degA; i++) { for (j = 0; j <= degB; j++) { if (i == 0) arb_swap(arb_mat_entry(R, degB, j), acb_realref(TB + j)); else arb_set(acb_mat_entry(R, degB + i, i + j), arb_mat_entry(R, degB, j)); } } arb_mat_det(acb_realref(D), R, prec); arb_mat_clear(R); } else { acb_mat_t C; acb_mat_init(C, degA + degB, degA + degB); for (i = 0; i < degB; i++) { for (j = 0; j <= degA; j++) { if (i == 0) acb_swap(acb_mat_entry(C, 0, j), TA + j); else acb_set(acb_mat_entry(C, i, i + j), acb_mat_entry(C, 0, j)); } } for (i = 0; i < degA; i++) { for (j = 0; j <= degB; j++) { if (i == 0) acb_swap(acb_mat_entry(C, degB, j), TB + j); else acb_set(acb_mat_entry(C, degB + i, i + j), acb_mat_entry(C, degB, j)); } } acb_mat_det(D, C, prec); acb_mat_clear(C); } result = !acb_contains_zero(D); _acb_vec_clear(TA, lenA); _acb_vec_clear(TB, lenB); acb_clear(D); return result; } /* assumes lenA >= lenB >= 1, and both A and B have nonzero leading coefficient */ slong _ca_poly_gcd(ca_ptr G, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, ca_ctx_t ctx) { if (_ca_vec_is_fmpq_vec(A, lenA, ctx) && _ca_vec_is_fmpq_vec(B, lenB, ctx)) { fmpz * zA, * zB, *zG; fmpz_t den; slong i; fmpz_init(den); zA = _fmpz_vec_init(lenA); zB = _fmpz_vec_init(lenB); zG = _fmpz_vec_init(lenA); _ca_vec_fmpq_vec_get_fmpz_vec_den(zA, den, A, lenA, ctx); _ca_vec_fmpq_vec_get_fmpz_vec_den(zB, den, B, lenB, ctx); _fmpz_poly_gcd(zG, zA, lenA, zB, lenB); while (lenA > 1 && fmpz_is_zero(zG + lenA - 1)) lenA--; for (i = 0; i < lenA; i++) ca_set_fmpz(G + i, zG + i, ctx); _fmpz_vec_clear(zA, lenA); _fmpz_vec_clear(zB, lenB); _fmpz_vec_clear(zG, lenA); return lenA; } if (_ca_poly_check_coprime_numerical(A, lenA, B, lenB, ctx)) { ca_one(G, ctx); return 1; } return _ca_poly_gcd_euclidean(G, A, lenA, B, lenB, ctx); } int ca_poly_gcd(ca_poly_t G, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx) { slong lenA = A->length, lenB = B->length, lenG; ca_ptr g; if (A->length == 0 && B->length == 0) { ca_poly_zero(G, ctx); return 1; } if (A->length == 0) return ca_poly_make_monic(G, B, ctx); if (B->length == 0) return ca_poly_make_monic(G, A, ctx); if (A->length < B->length) return ca_poly_gcd(G, B, A, ctx); if (ca_check_is_zero(A->coeffs + A->length - 1, ctx) != T_FALSE || ca_check_is_zero(B->coeffs + B->length - 1, ctx) != T_FALSE) { return 0; } /* lenA >= lenB >= 1 */ if (G == A || G == B) { g = _ca_vec_init(FLINT_MIN(lenA, lenB), ctx); } else { ca_poly_fit_length(G, FLINT_MIN(lenA, lenB), ctx); g = G->coeffs; } lenG = _ca_poly_gcd(g, A->coeffs, lenA, B->coeffs, lenB, ctx); if (G == A || G == B) { _ca_vec_clear(G->coeffs, G->alloc, ctx); G->coeffs = g; G->alloc = FLINT_MIN(lenA, lenB); G->length = FLINT_MIN(lenA, lenB); } _ca_poly_set_length(G, lenG, ctx); if (lenG == 0) { return 0; } else { if (G->length == 1) ca_one(G->coeffs, ctx); else ca_poly_make_monic(G, G, ctx); return 1; } } calcium-0.4.1/ca_poly/gcd_euclidean.c000066400000000000000000000100141407704557200175000ustar00rootroot00000000000000/* Copyright (C) 2011 William Hart Copyright (C) 2012 Andres Goens Copyright (C) 2013 Mike Hansen Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" #define CA_VEC_NORM(success, R, lenR, ctx) \ do { \ (success) = 1; \ while ((lenR) > 0) \ { \ truth_t is_zero; \ is_zero = ca_check_is_zero((R) + (lenR) - 1, (ctx)); \ if (is_zero == T_TRUE) \ (lenR)--; \ else if (is_zero == T_UNKNOWN) \ { \ (success) = 0; \ break; \ } \ else \ { \ break; \ } \ } \ } while (0) \ /* assumes lenA >= lenB >= 1, and both A and B have nonzero leading coefficient */ slong _ca_poly_gcd_euclidean(ca_ptr G, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, ca_ctx_t ctx) { const slong lenW = FLINT_MAX(lenA - lenB + 1, lenB) + lenA + 2 * lenB; ca_t invR3; ca_ptr Q, R1, R2, R3, T, W; slong lenR2, lenR3; int success; if (lenB == 1) { ca_one(G, ctx); return 1; } success = 1; /* lenA >= lenB > 1 */ ca_init(invR3, ctx); W = _ca_vec_init(lenW, ctx); Q = W; R1 = W + FLINT_MAX(lenA - lenB + 1, lenB); R2 = R1 + lenA; R3 = R2 + lenB; ca_inv(invR3, B + lenB - 1, ctx); _ca_poly_divrem(Q, R1, A, lenA, B, lenB, invR3, ctx); lenR3 = lenB - 1; CA_VEC_NORM(success, R1, lenR3, ctx); if (!success) goto cleanup; if (lenR3 == 0) { ca_clear(invR3, ctx); _ca_vec_set(G, B, lenB, ctx); _ca_vec_clear(W, lenW, ctx); return lenB; } T = R3; R3 = R1; R1 = T; _ca_vec_set(R2, B, lenB, ctx); lenR2 = lenB; do { ca_inv(invR3, R3 + (lenR3 - 1), ctx); _ca_poly_divrem(Q, R1, R2, lenR2, R3, lenR3, invR3, ctx); lenR2 = lenR3--; CA_VEC_NORM(success, R1, lenR3, ctx); if (!success) goto cleanup; T = R2; R2 = R3; R3 = R1; R1 = T; } while (lenR3 > 0); _ca_vec_set(G, R2, lenR2, ctx); cleanup: _ca_vec_clear(W, lenW, ctx); ca_clear(invR3, ctx); if (success) return lenR2; else return 0; } int ca_poly_gcd_euclidean(ca_poly_t G, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx) { slong lenA = A->length, lenB = B->length, lenG; ca_ptr g; if (A->length == 0 && B->length == 0) { ca_poly_zero(G, ctx); return 1; } if (A->length == 0) return ca_poly_make_monic(G, B, ctx); if (B->length == 0) return ca_poly_make_monic(G, A, ctx); if (A->length < B->length) return ca_poly_gcd_euclidean(G, B, A, ctx); if (ca_check_is_zero(A->coeffs + A->length - 1, ctx) != T_FALSE || ca_check_is_zero(B->coeffs + B->length - 1, ctx) != T_FALSE) { return 0; } /* lenA >= lenB >= 1 */ if (G == A || G == B) { g = _ca_vec_init(FLINT_MIN(lenA, lenB), ctx); } else { ca_poly_fit_length(G, FLINT_MIN(lenA, lenB), ctx); g = G->coeffs; } lenG = _ca_poly_gcd_euclidean(g, A->coeffs, lenA, B->coeffs, lenB, ctx); if (G == A || G == B) { _ca_vec_clear(G->coeffs, G->alloc, ctx); G->coeffs = g; G->alloc = FLINT_MIN(lenA, lenB); G->length = FLINT_MIN(lenA, lenB); } _ca_poly_set_length(G, lenG, ctx); if (lenG == 0) { return 0; } else { if (G->length == 1) ca_one(G->coeffs, ctx); else ca_poly_make_monic(G, G, ctx); return 1; } } calcium-0.4.1/ca_poly/get_fexpr.c000066400000000000000000000047701407704557200167310ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" #include "ca.h" #include "ca_ext.h" #include "ca_poly.h" void _ca_default_variables(fexpr_ptr ext_vars, slong num_ext); void _ca_get_fexpr_given_ext(fexpr_t res, const ca_t x, ulong flags, ca_ext_ptr * ext, slong num_ext, const fexpr_struct * ext_vars, ca_ctx_t ctx); void _ca_all_extensions(ca_ext_ptr ** extensions, slong * length, const ca_t x, ca_ctx_t ctx); void _ca_ext_get_fexpr_given_ext(fexpr_t res, const ca_ext_t x, ulong flags, ca_ext_ptr * ext, slong num_ext, const fexpr_struct * ext_vars, ca_ctx_t ctx); void ca_poly_get_fexpr(fexpr_t res, const ca_poly_t A, ulong flags, ca_ctx_t ctx) { ca_ext_ptr * ext; slong n, i, num_ext; fexpr_struct * ext_vars; fexpr_struct * where_args; fexpr_struct * coeffs; fexpr_t t, u; ext = NULL; num_ext = 0; n = A->length; if (n == 0) { fexpr_zero(res); return; } for (i = 0; i < n; i++) _ca_all_extensions(&ext, &num_ext, A->coeffs + i, ctx); ext_vars = _fexpr_vec_init(num_ext); fexpr_init(t); fexpr_init(u); _ca_default_variables(ext_vars, num_ext); coeffs = _fexpr_vec_init(n); for (i = 0; i < n; i++) _ca_get_fexpr_given_ext(coeffs + i, A->coeffs + i, flags, ext, num_ext, ext_vars, ctx); fexpr_set_symbol_builtin(t, FEXPR_List); fexpr_call_vec(u, t, coeffs, n); if (num_ext == 0) { fexpr_call_builtin1(res, FEXPR_Polynomial, u); } else { where_args = _fexpr_vec_init(num_ext + 1); fexpr_call_builtin1(where_args + 0, FEXPR_Polynomial, u); for (i = 0; i < num_ext; i++) { _ca_ext_get_fexpr_given_ext(t, ext[i], flags, ext, num_ext, ext_vars, ctx); fexpr_call_builtin2(where_args + i + 1, FEXPR_Def, ext_vars + i, t); } fexpr_set_symbol_builtin(t, FEXPR_Where); fexpr_call_vec(res, t, where_args, num_ext + 1); _fexpr_vec_clear(where_args, num_ext + 1); } _fexpr_vec_clear(coeffs, n); flint_free(ext); fexpr_clear(t); fexpr_clear(u); _fexpr_vec_clear(ext_vars, num_ext); } calcium-0.4.1/ca_poly/init.c000066400000000000000000000012301407704557200156750ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_init(ca_poly_t poly, ca_ctx_t ctx) { poly->coeffs = NULL; poly->length = 0; poly->alloc = 0; } void ca_poly_init2(ca_poly_t poly, slong len, ca_ctx_t ctx) { ca_poly_init(poly, ctx); ca_poly_fit_length(poly, len, ctx); } calcium-0.4.1/ca_poly/inlines.c000066400000000000000000000006641407704557200164050ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #define CA_POLY_INLINES_C #include "ca_poly.h" calcium-0.4.1/ca_poly/integral.c000066400000000000000000000016201407704557200165420ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_integral(ca_ptr res, ca_srcptr poly, slong len, ca_ctx_t ctx) { slong k = len - 1; for (k = len - 1; k > 0; k--) ca_div_ui(res + k, poly + k - 1, k, ctx); ca_zero(res, ctx); } void ca_poly_integral(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx) { ca_poly_fit_length(res, poly->length + 1, ctx); _ca_poly_integral(res->coeffs, poly->coeffs, poly->length + 1, ctx); _ca_poly_set_length(res, poly->length + 1, ctx); _ca_poly_normalise(res, ctx); } calcium-0.4.1/ca_poly/inv_series.c000066400000000000000000000102711407704557200171050ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" ca_field_ptr _ca_vec_same_field2(ca_srcptr A, slong Alen, ca_srcptr B, slong Blen, ca_ctx_t ctx); void _ca_poly_inv_series(ca_ptr Qinv, ca_srcptr Q, slong Qlen, slong len, ca_ctx_t ctx) { Qlen = FLINT_MIN(Qlen, len); if (CA_IS_SPECIAL(Q)) { if (ca_is_unknown(Q, ctx)) _ca_vec_unknown(Qinv, len, ctx); else _ca_vec_undefined(Qinv, len, ctx); return; } /* todo: tuning */ /* todo: shallow copy with integers */ if (Qlen >= 4 && _ca_vec_is_fmpq_vec(Q, Qlen, ctx) && !fmpq_is_zero(CA_FMPQ(Q))) { fmpz *p, *r; fmpz_t pden, rden; p = _fmpz_vec_init(Qlen); r = _fmpz_vec_init(len); fmpz_init(pden); fmpz_init(rden); _ca_vec_fmpq_vec_get_fmpz_vec_den(p, pden, Q, Qlen, ctx); _fmpq_poly_inv_series(r, rden, p, pden, Qlen, len); _ca_vec_set_fmpz_vec_div_fmpz(Qinv, r, rden, len, ctx); fmpz_clear(pden); fmpz_clear(rden); _fmpz_vec_clear(p, Qlen); _fmpz_vec_clear(r, len); return; } ca_inv(Qinv, Q, ctx); if (CA_IS_SPECIAL(Qinv)) { if (ca_is_unknown(Qinv, ctx)) _ca_vec_unknown(Qinv + 1, len - 1, ctx); else _ca_vec_undefined(Qinv + 1, len - 1, ctx); return; } if (Qlen == 1) { _ca_vec_zero(Qinv + 1, len - 1, ctx); } else if (len == 2) { ca_mul(Qinv + 1, Qinv, Qinv, ctx); ca_mul(Qinv + 1, Qinv + 1, Q + 1, ctx); ca_neg(Qinv + 1, Qinv + 1, ctx); } else { int is_one; ca_field_ptr K; slong i, blen; if (Qlen <= 8) { blen = len; } else { K = _ca_vec_same_field2(Q, Qlen, NULL, 0, ctx); /* Newton iteration where we have fast multiplication */ if (K != NULL && CA_FIELD_IS_NF(K)) { blen = 2 * qqbar_degree(CA_FIELD_NF_QQBAR(K)); blen = FLINT_MIN(blen, len); } else { blen = len; } } is_one = (ca_check_is_one(Qinv, ctx) == T_TRUE); for (i = 1; i < blen; i++) { ca_dot(Qinv + i, NULL, 1, Q + 1, 1, Qinv + i - 1, -1, FLINT_MIN(i, Qlen - 1), ctx); if (!is_one) ca_mul(Qinv + i, Qinv + i, Qinv, ctx); } if (len > blen) { slong Qnlen, Wlen, W2len; ca_ptr W; W = _ca_vec_init(len, ctx); NEWTON_INIT(blen, len) NEWTON_LOOP(m, n) Qnlen = FLINT_MIN(Qlen, n); Wlen = FLINT_MIN(Qnlen + m - 1, n); W2len = Wlen - m; _ca_poly_mullow(W, Q, Qnlen, Qinv, m, Wlen, ctx); _ca_poly_mullow(Qinv + m, Qinv, m, W + m, W2len, n - m, ctx); _ca_vec_neg(Qinv + m, Qinv + m, n - m, ctx); NEWTON_END_LOOP NEWTON_END _ca_vec_clear(W, len, ctx); } } } void ca_poly_inv_series(ca_poly_t Qinv, const ca_poly_t Q, slong len, ca_ctx_t ctx) { if (len == 0) { ca_poly_zero(Qinv, ctx); return; } if (Q->length == 0) { ca_poly_fit_length(Qinv, len, ctx); ca_uinf(Qinv->coeffs, ctx); _ca_vec_undefined(Qinv->coeffs + 1, len - 1, ctx); _ca_poly_set_length(Qinv, len, ctx); return; } if (Qinv == Q) { ca_poly_t t; ca_poly_init(t, ctx); ca_poly_inv_series(t, Q, len, ctx); ca_poly_swap(Qinv, t, ctx); ca_poly_clear(t, ctx); return; } ca_poly_fit_length(Qinv, len, ctx); _ca_poly_inv_series(Qinv->coeffs, Q->coeffs, Q->length, len, ctx); _ca_poly_set_length(Qinv, len, ctx); _ca_poly_normalise(Qinv, ctx); } calcium-0.4.1/ca_poly/is_proper.c000066400000000000000000000013431407704557200167410ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int ca_poly_is_proper(const ca_poly_t poly, ca_ctx_t ctx) { slong i, len; len = poly->length; for (i = 0; i < len; i++) if (CA_IS_SPECIAL(poly->coeffs + i)) return 0; if (len >= 1) if (ca_check_is_zero(poly->coeffs + len - 1, ctx) != T_FALSE) return 0; return 1; } calcium-0.4.1/ca_poly/log_series.c000066400000000000000000000056011407704557200170730ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_log_series(ca_ptr res, ca_srcptr f, slong flen, slong len, ca_ctx_t ctx) { flen = FLINT_MIN(flen, len); if (CA_IS_SPECIAL(f)) { if (ca_is_unknown(f, ctx)) _ca_vec_unknown(res, len, ctx); else _ca_vec_undefined(res, len, ctx); return; } if (flen == 1) { ca_log(res, f, ctx); _ca_vec_zero(res + 1, len - 1, ctx); } else if (len == 2) { ca_div(res + 1, f + 1, f + 0, ctx); /* safe since hlen >= 2 */ ca_log(res, f, ctx); } else if (_ca_vec_check_is_zero(f + 1, flen - 2, ctx) == T_TRUE) /* f = a + bx^d */ { slong i, j, d = flen - 1; for (i = 1, j = d; j < len; j += d, i++) { if (i == 1) ca_div(res + j, f + d, f + 0, ctx); else ca_mul(res + j, res + j - d, res + d, ctx); _ca_vec_zero(res + j - d + 1, flen - 2, ctx); } _ca_vec_zero(res + j - d + 1, len - (j - d + 1), ctx); for (i = 2, j = 2 * d; j < len; j += d, i++) ca_div_si(res + j, res + j, i % 2 ? i : -i, ctx); ca_log(res, f, ctx); /* done last to allow aliasing */ } else { ca_ptr f_diff, f_inv; ca_t a; slong alloc; alloc = len + flen - 1; f_inv = _ca_vec_init(alloc, ctx); f_diff = f_inv + len; ca_init(a, ctx); ca_log(a, f, ctx); _ca_poly_derivative(f_diff, f, flen, ctx); _ca_poly_inv_series(f_inv, f, flen, len, ctx); _ca_poly_mullow(res, f_inv, len - 1, f_diff, flen - 1, len - 1, ctx); _ca_poly_integral(res, res, len, ctx); ca_swap(res, a, ctx); ca_clear(a, ctx); _ca_vec_clear(f_inv, alloc, ctx); } if (ca_check_is_number(res, ctx) != T_TRUE) { if (ca_is_unknown(res, ctx)) _ca_vec_unknown(res + 1, len - 1, ctx); else _ca_vec_undefined(res + 1, len - 1, ctx); return; } } void ca_poly_log_series(ca_poly_t res, const ca_poly_t f, slong len, ca_ctx_t ctx) { if (len == 0) { ca_poly_zero(res, ctx); return; } ca_poly_fit_length(res, len, ctx); if (f->length == 0) { ca_neg_inf(res->coeffs, ctx); _ca_vec_undefined(res->coeffs + 1, len - 1, ctx); } else { _ca_poly_log_series(res->coeffs, f->coeffs, f->length, len, ctx); } _ca_poly_set_length(res, len, ctx); _ca_poly_normalise(res, ctx); } calcium-0.4.1/ca_poly/make_monic.c000066400000000000000000000027121407704557200170420ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int ca_poly_make_monic(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx) { if (poly->length == 0) { ca_poly_zero(res, ctx); return 0; } else { if (ca_check_is_one(poly->coeffs + poly->length - 1, ctx) == T_TRUE) { ca_poly_set(res, poly, ctx); ca_one(res->coeffs + res->length - 1, ctx); return 1; } if (ca_check_is_neg_one(poly->coeffs + poly->length - 1, ctx) == T_TRUE) { ca_poly_neg(res, poly, ctx); ca_one(res->coeffs + res->length - 1, ctx); return 1; } ca_poly_set(res, poly, ctx); ca_inv(res->coeffs + res->length - 1, res->coeffs + res->length - 1, ctx); if (CA_IS_SPECIAL(res->coeffs + res->length - 1)) { return 0; } else { _ca_vec_scalar_mul_ca(res->coeffs, res->coeffs, res->length - 1, res->coeffs + res->length - 1, ctx); ca_one(res->coeffs + res->length - 1, ctx); return 1; } } } calcium-0.4.1/ca_poly/mul.c000066400000000000000000000026431407704557200155400ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_mul(ca_ptr C, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, ca_ctx_t ctx) { _ca_poly_mullow(C, A, lenA, B, lenB, lenA + lenB - 1, ctx); } void ca_poly_mul(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) { slong len_out; if ((poly1->length == 0) || (poly2->length == 0)) { ca_poly_zero(res, ctx); return; } len_out = poly1->length + poly2->length - 1; if (res == poly1 || res == poly2) { ca_poly_t temp; ca_poly_init2(temp, len_out, ctx); _ca_poly_mul(temp->coeffs, poly1->coeffs, poly1->length, poly2->coeffs, poly2->length, ctx); ca_poly_swap(res, temp, ctx); ca_poly_clear(temp, ctx); } else { ca_poly_fit_length(res, len_out, ctx); _ca_poly_mul(res->coeffs, poly1->coeffs, poly1->length, poly2->coeffs, poly2->length, ctx); } _ca_poly_set_length(res, len_out, ctx); } calcium-0.4.1/ca_poly/mullow.c000066400000000000000000000205151407704557200162600ustar00rootroot00000000000000/* Copyright (C) 2020, 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" ca_field_ptr _ca_vec_same_field2(ca_srcptr A, slong Alen, ca_srcptr B, slong Blen, ca_ctx_t ctx) { ca_field_ptr K; ca_field_ptr QQ; slong i; QQ = ctx->field_qq; K = QQ; for (i = 0; i < Alen; i++) { if (CA_IS_QQ(A + i, ctx)) continue; if (CA_IS_SPECIAL(A + i)) return NULL; if (K == QQ) K = CA_FIELD(A + i, ctx); else if (K != CA_FIELD(A + i, ctx)) return NULL; } if (B != NULL) { for (i = 0; i < Blen; i++) { if (CA_IS_QQ(B + i, ctx)) continue; if (CA_IS_SPECIAL(B + i)) return NULL; if (K == QQ) K = CA_FIELD(B + i, ctx); else if (K != CA_FIELD(B + i, ctx)) return NULL; } } return K; } static void _ca_addmul(ca_t x, ca_t tmp, const ca_t a, const ca_t b, ca_ctx_t ctx) { ca_mul(tmp, a, b, ctx); ca_add(x, x, tmp, ctx); } static void _ca_poly_sqrlow_classical(ca_ptr res, ca_srcptr poly1, slong len1, slong n, ca_ctx_t ctx) { slong i, start, stop; ca_t t; /* Basecase squaring */ ca_init(t, ctx); ca_sqr(res, poly1, ctx); ca_mul(res + 1, poly1, poly1 + 1, ctx); ca_mul_ui(res + 1, res + 1, 2, ctx); for (i = 2; i < FLINT_MIN(n, 2 * len1 - 3); i++) { start = FLINT_MAX(0, i - len1 + 1); stop = FLINT_MIN(len1 - 1, (i + 1) / 2 - 1); ca_dot(res + i, NULL, 0, poly1 + start, 1, poly1 + i - start, -1, stop - start + 1, ctx); ca_mul_ui(res + i, res + i, 2, ctx); if (i % 2 == 0 && i / 2 < len1) _ca_addmul(res + i, t, poly1 + i / 2, poly1 + i / 2, ctx); } if (len1 > 2 && n >= 2 * len1 - 2) { ca_mul(res + 2 * len1 - 3, poly1 + len1 - 1, poly1 + len1 - 2, ctx); ca_mul_ui(res + 2 * len1 - 3, res + 2 * len1 - 3, 2, ctx); } if (n >= 2 * len1 - 1) ca_sqr(res + 2 * len1 - 2, poly1 + len1 - 1, ctx); ca_clear(t, ctx); } static void _ca_poly_sqrlow_fmpqs(ca_ptr res, ca_srcptr poly1, slong len1, slong n, ca_ctx_t ctx) { fmpz *z1, *z3; fmpz_t den1; if (_ca_vec_fmpq_vec_is_fmpz_vec(poly1, len1, ctx)) { slong i; z1 = _fmpz_vec_init(len1 + n); z3 = z1 + len1; for (i = 0; i < len1; i++) z1[i] = *CA_FMPQ_NUMREF(poly1 + i); _fmpz_poly_sqrlow(z3, z1, len1, n); for (i = 0; i < n; i++) { _ca_make_fmpq(res + i, ctx); fmpz_one(CA_FMPQ_DENREF(res + i)); fmpz_clear(CA_FMPQ_NUMREF(res + i)); *CA_FMPQ_NUMREF(res + i) = z3[i]; } flint_free(z1); } else { fmpz_init(den1); z1 = _fmpz_vec_init(len1 + n); z3 = z1 + len1; _ca_vec_fmpq_vec_get_fmpz_vec_den(z1, den1, poly1, len1, ctx); fmpz_mul(den1, den1, den1); _fmpz_poly_sqrlow(z3, z1, len1, n); _ca_vec_set_fmpz_vec_div_fmpz(res, z3, den1, n, ctx); _fmpz_vec_clear(z1, len1 + n); fmpz_clear(den1); } } static void _ca_poly_mullow_fmpqs(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, slong n, ca_ctx_t ctx) { fmpz *z1, *z2, *z3; fmpz_t den1, den2; /* Todo: handle mixed cases */ if (_ca_vec_fmpq_vec_is_fmpz_vec(poly1, len1, ctx) && _ca_vec_fmpq_vec_is_fmpz_vec(poly2, len2, ctx)) { slong i; z1 = _fmpz_vec_init(len1 + len2 + n); z2 = z1 + len1; z3 = z2 + len2; for (i = 0; i < len1; i++) z1[i] = *CA_FMPQ_NUMREF(poly1 + i); for (i = 0; i < len2; i++) z2[i] = *CA_FMPQ_NUMREF(poly2 + i); if (len1 >= len2) _fmpz_poly_mullow(z3, z1, len1, z2, len2, n); else _fmpz_poly_mullow(z3, z2, len2, z1, len1, n); for (i = 0; i < n; i++) { _ca_make_fmpq(res + i, ctx); fmpz_one(CA_FMPQ_DENREF(res + i)); fmpz_clear(CA_FMPQ_NUMREF(res + i)); *CA_FMPQ_NUMREF(res + i) = z3[i]; } flint_free(z1); } else { fmpz_init(den1); fmpz_init(den2); z1 = _fmpz_vec_init(len1 + len2 + n); z2 = z1 + len1; z3 = z2 + len2; _ca_vec_fmpq_vec_get_fmpz_vec_den(z1, den1, poly1, len1, ctx); _ca_vec_fmpq_vec_get_fmpz_vec_den(z2, den2, poly2, len2, ctx); fmpz_mul(den1, den1, den2); if (len1 >= len2) _fmpz_poly_mullow(z3, z1, len1, z2, len2, n); else _fmpz_poly_mullow(z3, z2, len2, z1, len1, n); _ca_vec_set_fmpz_vec_div_fmpz(res, z3, den1, n, ctx); _fmpz_vec_clear(z1, len1 + len2 + n); fmpz_clear(den1); fmpz_clear(den2); } } void _ca_poly_mullow(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, slong n, ca_ctx_t ctx) { ca_field_ptr K; len1 = FLINT_MIN(len1, n); len2 = FLINT_MIN(len2, n); if (n == 1) { ca_mul(res, poly1, poly2, ctx); return; } if (len1 == 1) { _ca_vec_scalar_mul_ca(res, poly2, n, poly1, ctx); return; } if (len2 == 1) { _ca_vec_scalar_mul_ca(res, poly1, n, poly2, ctx); return; } /* Squaring */ if (poly1 == poly2 && len1 == len2) { /* Integers and rationals. */ if (len1 >= 4 && _ca_vec_is_fmpq_vec(poly1, len1, ctx)) { _ca_poly_sqrlow_fmpqs(res, poly1, len1, n, ctx); return; } /* Square over the same number field. */ if (len1 >= 4) { K = _ca_vec_same_field2(poly1, len1, NULL, 0, ctx); if (K != NULL && CA_FIELD_IS_NF(K) && (FLINT_MIN(len1, len2) >= CA_FIELD_NF(K)->pol->length || FLINT_MIN(len1, len2) >= 10)) { _ca_poly_mullow_same_nf(res, poly1, len1, poly2, len2, n, K, ctx); return; } } _ca_poly_sqrlow_classical(res, poly1, len1, n, ctx); return; } if (len1 >= 4 && len2 >= 4 && _ca_vec_is_fmpq_vec(poly1, len1, ctx) && _ca_vec_is_fmpq_vec(poly2, len2, ctx)) { _ca_poly_mullow_fmpqs(res, poly1, len1, poly2, len2, n, ctx); return; } /* Multiply over the same number field. */ if (len1 >= 4) { K = _ca_vec_same_field2(poly1, len1, poly2, len2, ctx); if (K != NULL && CA_FIELD_IS_NF(K) && (FLINT_MIN(len1, len2) >= CA_FIELD_NF(K)->pol->length || FLINT_MIN(len1, len2) >= 10)) { _ca_poly_mullow_same_nf(res, poly1, len1, poly2, len2, n, K, ctx); return; } } /* General case */ { slong i, top1, top2; ca_mul(res, poly1, poly2, ctx); for (i = 1; i < n; i++) { top1 = FLINT_MIN(len1 - 1, i); top2 = FLINT_MIN(len2 - 1, i); ca_dot(res + i, NULL, 0, poly1 + i - top2, 1, poly2 + top2, -1, top1 + top2 - i + 1, ctx); } } } void ca_poly_mullow(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, slong n, ca_ctx_t ctx) { slong len_out; if (poly1->length == 0 || poly2->length == 0 || n == 0) { ca_poly_zero(res, ctx); return; } len_out = poly1->length + poly2->length - 1; n = FLINT_MIN(n, len_out); if (res == poly1 || res == poly2) { ca_poly_t t; ca_poly_init2(t, n, ctx); _ca_poly_mullow(t->coeffs, poly1->coeffs, poly1->length, poly2->coeffs, poly2->length, n, ctx); ca_poly_swap(res, t, ctx); ca_poly_clear(t, ctx); } else { ca_poly_fit_length(res, n, ctx); _ca_poly_mullow(res->coeffs, poly1->coeffs, poly1->length, poly2->coeffs, poly2->length, n, ctx); } _ca_poly_set_length(res, n, ctx); _ca_poly_normalise(res, ctx); } calcium-0.4.1/ca_poly/mullow_same_nf.c000066400000000000000000000107201407704557200177450ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" static const fmpz * _nf_denref(const nf_elem_t a, const nf_t nf) { if (nf->flag & NF_LINEAR) return LNF_ELEM_DENREF(a); else if (nf->flag & NF_QUADRATIC) return QNF_ELEM_DENREF(a); else return NF_ELEM_DENREF(a); } /* writes used coefficients; does not write padding zeros */ static void _nf_elem_get_fmpz_poly_lcm(fmpz * pol, fmpz_t t, const nf_elem_t a, const fmpz_t lcm, const nf_t nf) { fmpz_divexact(t, lcm, _nf_denref(a, nf)); if (nf->flag & NF_LINEAR) fmpz_mul(pol, t, LNF_ELEM_NUMREF(a)); else if (nf->flag & NF_QUADRATIC) _fmpz_vec_scalar_mul_fmpz(pol, QNF_ELEM_NUMREF(a), 2, t); else _fmpz_vec_scalar_mul_fmpz(pol, NF_ELEM(a)->coeffs, NF_ELEM(a)->length, t); } static int get_lcm(fmpz_t Aden, ca_srcptr A, slong Alen, ca_field_t K, slong bits_limit, ca_ctx_t ctx) { slong i; fmpz_one(Aden); for (i = 0; i < Alen; i++) { if (CA_IS_QQ(A + i, ctx)) fmpz_lcm(Aden, Aden, CA_FMPQ_DENREF(A + i)); else fmpz_lcm(Aden, Aden, _nf_denref(CA_NF_ELEM(A + i), CA_FIELD_NF(K))); if (fmpz_bits(Aden) > bits_limit) return 0; } return 1; } void _ca_set_nf_fmpz_poly_den(ca_t res, const fmpz_poly_t poly, const fmpz_t den, ca_field_t K, ca_ctx_t ctx); void _ca_poly_mullow_same_nf(ca_ptr C, ca_srcptr A, slong Alen, ca_srcptr B, slong Blen, slong len, ca_field_t K, ca_ctx_t ctx) { fmpz_t Aden, Bden; fmpz_t den, t; slong deg, m; fmpz *ZA, *ZB, *ZC; int squaring; slong i; Alen = FLINT_MIN(Alen, len); Blen = FLINT_MIN(Blen, len); if (!CA_FIELD_IS_NF(K)) { flint_printf("_ca_poly_mullow_same_nf: expected a number field\n"); flint_abort(); } squaring = (A == B) && (Alen == Blen); fmpz_init(Aden); fmpz_init(Bden); if (!get_lcm(Aden, A, Alen, K, WORD_MAX, ctx) || (!squaring && !get_lcm(Bden, B, Blen, K, WORD_MAX, ctx))) { flint_abort(); /* fmpz_clear(Aden); fmpz_clear(Bden); _ca_poly_mullow_classical(C, A, Alen, B, Blen, len, ctx); return; */ } fmpz_init(den); fmpz_init(t); /* Todo: could inspect elements to get degree bounds */ deg = CA_FIELD_NF(K)->pol->length - 1; /* Packing length */ m = 2 * deg - 1; ZA = _fmpz_vec_init(Alen * m); if (squaring) ZB = ZA; else ZB = _fmpz_vec_init(Blen * m); ZC = _fmpz_vec_init(len * m); for (i = 0; i < Alen; i++) { if (CA_IS_QQ(A + i, ctx)) { fmpz_divexact(t, Aden, CA_FMPQ_DENREF(A + i)); fmpz_mul(ZA + i * m + 0, t, CA_FMPQ_NUMREF(A + i)); } else { _nf_elem_get_fmpz_poly_lcm(ZA + i * m, t, CA_NF_ELEM(A + i), Aden, CA_FIELD_NF(K)); } } if (!squaring) { for (i = 0; i < Blen; i++) { if (CA_IS_QQ(B + i, ctx)) { fmpz_divexact(t, Bden, CA_FMPQ_DENREF(B + i)); fmpz_mul(ZB + i * m + 0, t, CA_FMPQ_NUMREF(B + i)); } else { _nf_elem_get_fmpz_poly_lcm(ZB + i * m, t, CA_NF_ELEM(B + i), Bden, CA_FIELD_NF(K)); } } } if (squaring) { _fmpz_poly_sqrlow(ZC, ZA, Alen * m, len * m); fmpz_mul(den, Aden, Aden); } else { if (Alen >= Blen) _fmpz_poly_mullow(ZC, ZA, Alen * m, ZB, Blen * m, len * m); else _fmpz_poly_mullow(ZC, ZB, Blen * m, ZA, Alen * m, len * m); fmpz_mul(den, Aden, Bden); } for (i = 0; i < len; i++) { fmpz_poly_t poly; poly->coeffs = ZC + i * m; poly->length = m; while (poly->length > 0 && fmpz_is_zero(poly->coeffs + poly->length - 1)) poly->length--; _ca_set_nf_fmpz_poly_den(C + i, poly, den, K, ctx); } _fmpz_vec_clear(ZA, Alen * m); if (!squaring) _fmpz_vec_clear(ZB, Blen * m); _fmpz_vec_clear(ZC, len * m); fmpz_clear(Aden); fmpz_clear(Bden); fmpz_clear(den); fmpz_clear(t); } calcium-0.4.1/ca_poly/neg.c000066400000000000000000000011751407704557200155130ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_neg(ca_poly_t res, const ca_poly_t src, ca_ctx_t ctx) { ca_poly_fit_length(res, src->length, ctx); _ca_vec_neg(res->coeffs, src->coeffs, src->length, ctx); _ca_poly_set_length(res, src->length, ctx); } calcium-0.4.1/ca_poly/normalise.c000066400000000000000000000012431407704557200167270ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_normalise(ca_poly_t poly, ca_ctx_t ctx) { slong i; i = poly->length - 1; while (i >= 0 && (ca_check_is_zero(poly->coeffs + i, ctx) == T_TRUE)) { ca_zero(poly->coeffs + i, ctx); i--; } poly->length = i + 1; } calcium-0.4.1/ca_poly/pow_ui.c000066400000000000000000000027141407704557200162440ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_pow_ui(ca_ptr res, ca_srcptr f, slong flen, ulong exp, ca_ctx_t ctx) { _ca_poly_pow_ui_trunc(res, f, flen, exp, exp * (flen - 1) + 1, ctx); } void ca_poly_pow_ui(ca_poly_t res, const ca_poly_t poly, ulong exp, ca_ctx_t ctx) { slong flen, rlen; flen = poly->length; if (exp == 0) { ca_poly_one(res, ctx); } else if (flen == 0) { ca_poly_zero(res, ctx); } else { rlen = exp * (flen - 1) + 1; if (res != poly) { ca_poly_fit_length(res, rlen, ctx); _ca_poly_pow_ui(res->coeffs, poly->coeffs, flen, exp, ctx); _ca_poly_set_length(res, rlen, ctx); _ca_poly_normalise(res, ctx); } else { ca_poly_t t; ca_poly_init2(t, rlen, ctx); _ca_poly_pow_ui(t->coeffs, poly->coeffs, flen, exp, ctx); _ca_poly_set_length(t, rlen, ctx); _ca_poly_normalise(t, ctx); ca_poly_swap(res, t, ctx); ca_poly_clear(t, ctx); } } } calcium-0.4.1/ca_poly/pow_ui_trunc.c000066400000000000000000000063571407704557200174660ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" #define MUL(z, zlen, x, xlen, y, ylen, trunc, ctx) \ do { \ slong slen = FLINT_MIN(xlen + ylen - 1, trunc); \ _ca_poly_mullow(z, x, xlen, y, ylen, slen, ctx); \ zlen = slen; \ } while (0) void _ca_poly_pow_ui_trunc(ca_ptr res, ca_srcptr f, slong flen, ulong exp, slong len, ca_ctx_t ctx) { ca_ptr v, R, S, T; slong rlen; ulong bit; if (exp <= 1) { if (exp == 0) ca_one(res, ctx); else if (exp == 1) _ca_vec_set(res, f, len, ctx); return; } /* (f * x^r)^m = x^(rm) * f^m */ while (flen > 1 && (ca_check_is_zero(f, ctx) == T_TRUE)) { if (((ulong) len) > exp) { _ca_vec_zero(res, exp, ctx); len -= exp; res += exp; } else { _ca_vec_zero(res, len, ctx); return; } f++; flen--; } if (exp == 2) { _ca_poly_mullow(res, f, flen, f, flen, len, ctx); return; } if (flen == 1) { ca_pow_ui(res, f, exp, ctx); return; } v = _ca_vec_init(len, ctx); bit = UWORD(1) << (FLINT_BIT_COUNT(exp) - 2); if (n_zerobits(exp) % 2) { R = res; S = v; } else { R = v; S = res; } MUL(R, rlen, f, flen, f, flen, len, ctx); if (bit & exp) { MUL(S, rlen, R, rlen, f, flen, len, ctx); T = R; R = S; S = T; } while (bit >>= 1) { if (bit & exp) { MUL(S, rlen, R, rlen, R, rlen, len, ctx); MUL(R, rlen, S, rlen, f, flen, len, ctx); } else { MUL(S, rlen, R, rlen, R, rlen, len, ctx); T = R; R = S; S = T; } } _ca_vec_clear(v, len, ctx); } void ca_poly_pow_ui_trunc(ca_poly_t res, const ca_poly_t poly, ulong exp, slong len, ca_ctx_t ctx) { slong flen, rlen; flen = poly->length; if (exp == 0 && len != 0) { ca_poly_one(res, ctx); } else if (flen == 0 || len == 0) { ca_poly_zero(res, ctx); } else { rlen = poly_pow_length(flen, exp, len); if (res != poly) { ca_poly_fit_length(res, rlen, ctx); _ca_poly_pow_ui_trunc(res->coeffs, poly->coeffs, flen, exp, rlen, ctx); _ca_poly_set_length(res, rlen, ctx); _ca_poly_normalise(res, ctx); } else { ca_poly_t t; ca_poly_init2(t, rlen, ctx); _ca_poly_pow_ui_trunc(t->coeffs, poly->coeffs, flen, exp, rlen, ctx); _ca_poly_set_length(t, rlen, ctx); _ca_poly_normalise(t, ctx); ca_poly_swap(res, t, ctx); ca_poly_clear(t, ctx); } } } calcium-0.4.1/ca_poly/print.c000066400000000000000000000020301407704557200160650ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_print(const ca_poly_t poly, ca_ctx_t ctx) { slong i, len; len = poly->length; flint_printf("ca_poly of length %wd:\n", len); for (i = 0; i < len; i++) { flint_printf(" "); ca_print(poly->coeffs + i, ctx); flint_printf("\n"); } flint_printf("\n"); } void ca_poly_printn(const ca_poly_t poly, slong digits, ca_ctx_t ctx) { slong len, i; len = poly->length; flint_printf("["); for (i = 0; i < len; i++) { ca_printn(poly->coeffs + i, digits, ctx); if (i < len - 1) flint_printf(", "); } flint_printf("]\n"); } calcium-0.4.1/ca_poly/randtest.c000066400000000000000000000020751407704557200165660ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_randtest(ca_poly_t poly, flint_rand_t state, slong len, slong depth, slong bits, ca_ctx_t ctx) { slong i; ca_poly_fit_length(poly, len, ctx); for (i = 0; i < len; i++) ca_randtest(poly->coeffs + i, state, depth, bits, ctx); _ca_poly_set_length(poly, len, ctx); _ca_poly_normalise(poly, ctx); } void ca_poly_randtest_rational(ca_poly_t poly, flint_rand_t state, slong len, slong bits, ca_ctx_t ctx) { slong i; ca_poly_fit_length(poly, len, ctx); for (i = 0; i < len; i++) ca_randtest_rational(poly->coeffs + i, state, bits, ctx); _ca_poly_set_length(poly, len, ctx); _ca_poly_normalise(poly, ctx); } calcium-0.4.1/ca_poly/reverse.c000066400000000000000000000025421407704557200164140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_reverse(ca_ptr res, ca_srcptr poly, slong len, slong n, ca_ctx_t ctx) { if (res == poly) { slong i; for (i = 0; i < n / 2; i++) { ca_struct t = res[i]; res[i] = res[n - 1 - i]; res[n - 1 - i] = t; } for (i = 0; i < n - len; i++) ca_zero(res + i, ctx); } else { slong i; for (i = 0; i < n - len; i++) ca_zero(res + i, ctx); for (i = 0; i < len; i++) ca_set(res + (n - len) + i, poly + (len - 1) - i, ctx); } } void ca_poly_reverse(ca_poly_t res, const ca_poly_t poly, slong n, ca_ctx_t ctx) { slong len = FLINT_MIN(n, poly->length); if (len == 0) { ca_poly_zero(res, ctx); return; } ca_poly_fit_length(res, n, ctx); _ca_poly_reverse(res->coeffs, poly->coeffs, len, n, ctx); _ca_poly_set_length(res, n, ctx); _ca_poly_normalise(res, ctx); } calcium-0.4.1/ca_poly/roots.c000066400000000000000000000156531407704557200161160ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_roots_quadratic(ca_t r1, ca_t r2, const ca_t a, const ca_t b, const ca_t c, ca_ctx_t ctx) { ca_t d, t; ca_init(d, ctx); ca_init(t, ctx); ca_mul(t, a, c, ctx); ca_mul_ui(t, t, 4, ctx); ca_sqr(d, b, ctx); ca_sub(d, d, t, ctx); ca_sqrt(d, d, ctx); ca_inv(t, a, ctx); ca_div_ui(t, t, 2, ctx); ca_sub(r1, d, b, ctx); ca_add(r2, b, d, ctx); ca_neg(r2, r2, ctx); ca_mul(r1, r1, t, ctx); ca_mul(r2, r2, t, ctx); ca_clear(d, ctx); ca_clear(t, ctx); } /* exp(2 pi i * (1 / 3)) */ /* todo: make this faster to construct */ void ca_omega(ca_t res, ca_ctx_t ctx) { ca_pi_i(res, ctx); ca_mul_ui(res, res, 2, ctx); ca_div_ui(res, res, 3, ctx); ca_exp(res, res, ctx); } /* Solves a cubic equation using the cubic formula. Assumes (does not check) that a is invertible. */ int _ca_poly_roots_cubic(ca_t r1, ca_t r2, ca_t r3, const ca_t a, const ca_t b, const ca_t c, const ca_t d, ca_ctx_t ctx) { ca_t D0, D1, C, w1, w2, t; int success; ca_init(D0, ctx); ca_init(D1, ctx); ca_init(C, ctx); ca_init(w1, ctx); ca_init(w2, ctx); ca_init(t, ctx); /* D0 = b^2 - 3*a*c */ ca_sqr(D0, b, ctx); ca_mul(t, a, c, ctx); ca_mul_ui(t, t, 3, ctx); ca_sub(D0, D0, t, ctx); /* D1 = b*(2*b^2 - 9*a*c) + 27*a^2*d */ ca_sqr(D1, b, ctx); ca_mul_ui(D1, D1, 2, ctx); ca_mul(t, a, c, ctx); ca_mul_ui(t, t, 9, ctx); ca_sub(D1, D1, t, ctx); ca_mul(D1, D1, b, ctx); ca_sqr(t, a, ctx); ca_mul(t, t, d, ctx); ca_mul_ui(t, t, 27, ctx); ca_add(D1, D1, t, ctx); ca_sqr(C, D1, ctx); ca_sqr(t, D0, ctx); ca_mul(t, t, D0, ctx); ca_mul_ui(t, t, 4, ctx); ca_sub(C, C, t, ctx); ca_sqrt(C, C, ctx); /* C = (D1 + sqrt(D1^2 - 4*D0^3)) / 2 or (D1 - sqrt(D1^2 - 4*D0^3)) / 2, whichever is nonzero */ success = 1; ca_add(t, D1, C, ctx); if (ca_check_is_zero(t, ctx) == T_FALSE) { ca_swap(C, t, ctx); } else if (ca_check_is_zero(t, ctx) != T_FALSE) { ca_sub(t, D1, C, ctx); if (ca_check_is_zero(t, ctx) == T_FALSE) ca_swap(C, t, ctx); else success = 0; } if (success) { ca_div_ui(C, C, 2, ctx); /* C = C^(1/3) */ ca_set_ui(t, 1, ctx); ca_div_ui(t, t, 3, ctx); ca_pow(C, C, t, ctx); /* w1 = exp(2 pi i * (1 / 3)) */ /* w2 = exp(2 pi i * (2 / 3)) = w1^2 */ ca_omega(w1, ctx); ca_sqr(w2, w1, ctx); /* r1 = (b + C + D0 / C) / (-3*a) */ /* r2 = (b + w1*C + w2 * D0 / C) / (-3*a) */ /* r3 = (b + w2*C + w1 * D0 / C) / (-3*a) */ ca_div(r1, D0, C, ctx); ca_mul(r2, r1, w2, ctx); ca_mul(r3, r1, w1, ctx); ca_add(r1, r1, C, ctx); ca_mul(t, w1, C, ctx); ca_add(r2, r2, t, ctx); ca_mul(t, w2, C, ctx); ca_add(r3, r3, t, ctx); ca_add(r1, r1, b, ctx); ca_add(r2, r2, b, ctx); ca_add(r3, r3, b, ctx); ca_mul_si(t, a, -3, ctx); ca_inv(t, t, ctx); ca_mul(r1, r1, t, ctx); ca_mul(r2, r2, t, ctx); ca_mul(r3, r3, t, ctx); } else { ca_unknown(r1, ctx); ca_unknown(r2, ctx); ca_unknown(r3, ctx); } ca_clear(D0, ctx); ca_clear(D1, ctx); ca_clear(C, ctx); ca_clear(w1, ctx); ca_clear(w2, ctx); ca_clear(t, ctx); return success; } int _ca_poly_roots(ca_ptr roots, ca_srcptr poly, slong len, ca_ctx_t ctx) { slong deg; truth_t leading_zero; if (len == 0) return 0; deg = len - 1; leading_zero = ca_check_is_zero(poly + deg, ctx); if (leading_zero != T_FALSE) return 0; while (deg > 1 && ca_check_is_zero(poly, ctx) == T_TRUE) { ca_zero(roots, ctx); roots++; poly++; len--; deg--; } if (deg == 0) return 1; if (deg == 1) { ca_div(roots, poly, poly + 1, ctx); ca_neg(roots, roots, ctx); return 1; } if (_ca_vec_is_fmpq_vec(poly, len, ctx)) { fmpz_poly_t f; qqbar_ptr r; slong i; f->coeffs = _fmpz_vec_init(len); f->length = f->alloc = len; r = _qqbar_vec_init(len - 1); if (_ca_vec_fmpq_vec_is_fmpz_vec(poly, len, ctx)) { for (i = 0; i < len; i++) fmpz_set(f->coeffs + i, CA_FMPQ_NUMREF(poly + i)); } else { fmpz_t t; fmpz_init(t); fmpz_one(t); for (i = 0; i < len; i++) fmpz_lcm(t, t, CA_FMPQ_DENREF(poly + i)); for (i = 0; i < len; i++) { fmpz_divexact(f->coeffs + i, t, CA_FMPQ_DENREF(poly + i)); fmpz_mul(f->coeffs + i, f->coeffs + i, CA_FMPQ_NUMREF(poly + i)); } fmpz_clear(t); } qqbar_roots_fmpz_poly(r, f, 0); for (i = 0; i < deg; i++) ca_set_qqbar(roots + i, r + i, ctx); _fmpz_vec_clear(f->coeffs, len); _qqbar_vec_clear(r, len - 1); return 1; } if (deg == 2) { _ca_poly_roots_quadratic(roots, roots + 1, poly + 2, poly + 1, poly + 0, ctx); return 1; } if (deg == 3) { return _ca_poly_roots_cubic(roots, roots + 1, roots + 2, poly + 3, poly + 2, poly + 1, poly + 0, ctx); } return 0; } int ca_poly_roots(ca_vec_t roots, ulong * exp, const ca_poly_t poly, ca_ctx_t ctx) { ca_poly_vec_t fac; ca_t c; slong i, j, num_roots, factor_deg; int success; ulong * fac_exp; if (poly->length == 0) return 0; ca_poly_vec_init(fac, 0, ctx); ca_init(c, ctx); fac_exp = flint_malloc(sizeof(ulong) * poly->length); success = ca_poly_factor_squarefree(c, fac, fac_exp, poly, ctx); if (success) { num_roots = 0; for (i = 0; i < fac->length; i++) num_roots += (fac->entries + i)->length - 1; ca_vec_set_length(roots, num_roots, ctx); num_roots = 0; for (i = 0; success && i < fac->length; i++) { factor_deg = (fac->entries + i)->length - 1; success = _ca_poly_roots(roots->entries + num_roots, (fac->entries + i)->coeffs, (fac->entries + i)->length, ctx); for (j = 0; j < factor_deg; j++) exp[num_roots + j] = fac_exp[i]; num_roots += factor_deg; } } ca_poly_vec_clear(fac, ctx); ca_clear(c, ctx); flint_free(fac_exp); return success; } calcium-0.4.1/ca_poly/set.c000066400000000000000000000011751407704557200155350ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_set(ca_poly_t res, const ca_poly_t src, ca_ctx_t ctx) { ca_poly_fit_length(res, src->length, ctx); _ca_vec_set(res->coeffs, src->coeffs, src->length, ctx); _ca_poly_set_length(res, src->length, ctx); } calcium-0.4.1/ca_poly/set_ca.c000066400000000000000000000013071407704557200161750ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_set_ca(ca_poly_t poly, const ca_t x, ca_ctx_t ctx) { if (ca_check_is_zero(x, ctx) == T_TRUE) { ca_poly_zero(poly, ctx); } else { ca_poly_fit_length(poly, 1, ctx); ca_set(poly->coeffs, x, ctx); _ca_poly_set_length(poly, 1, ctx); } } calcium-0.4.1/ca_poly/set_coeff_ca.c000066400000000000000000000013641407704557200173420ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_set_coeff_ca(ca_poly_t poly, slong n, const ca_t x, ca_ctx_t ctx) { ca_poly_fit_length(poly, n + 1, ctx); if (n + 1 > poly->length) { _ca_vec_zero(poly->coeffs + poly->length, n - poly->length, ctx); poly->length = n + 1; } ca_set(poly->coeffs + n, x, ctx); _ca_poly_normalise(poly, ctx); } calcium-0.4.1/ca_poly/set_fmpq_poly.c000066400000000000000000000017451407704557200176260ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_set_fmpq_poly(ca_poly_t res, const fmpq_poly_t src, ca_ctx_t ctx) { slong i; ca_poly_fit_length(res, src->length, ctx); if (fmpz_is_one(fmpq_poly_denref(src))) { for (i = 0; i < src->length; i++) ca_set_fmpz(res->coeffs + i, src->coeffs + i, ctx); } else { for (i = 0; i < src->length; i++) { ca_set_fmpz(res->coeffs + i, src->coeffs + i, ctx); ca_div_fmpz(res->coeffs + i, res->coeffs + i, fmpq_poly_denref(src), ctx); } } _ca_poly_set_length(res, src->length, ctx); } calcium-0.4.1/ca_poly/set_fmpz_poly.c000066400000000000000000000012731407704557200176330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_set_fmpz_poly(ca_poly_t res, const fmpz_poly_t src, ca_ctx_t ctx) { slong i; ca_poly_fit_length(res, src->length, ctx); for (i = 0; i < src->length; i++) ca_set_fmpz(res->coeffs + i, src->coeffs + i, ctx); _ca_poly_set_length(res, src->length, ctx); } calcium-0.4.1/ca_poly/set_length.c000066400000000000000000000012101407704557200170640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_set_length(ca_poly_t poly, slong len, ca_ctx_t ctx) { slong i; if (poly->length > len) { for (i = len; i < poly->length; i++) ca_zero(poly->coeffs + i, ctx); } poly->length = len; } calcium-0.4.1/ca_poly/set_roots.c000066400000000000000000000047701407704557200167670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_set_roots(ca_ptr poly, ca_srcptr xs, const ulong * exp, slong n, ca_ctx_t ctx) { if (n == 0 || (n == 1 && exp[0] == 0)) { ca_one(poly, ctx); } else if (n == 1) { if (exp[0] == 1) { ca_neg(poly, xs, ctx); ca_one(poly + 1, ctx); } else if (exp[0] == 2) { ca_sqr(poly, xs, ctx); ca_mul_si(poly + 1, xs, -2, ctx); ca_one(poly + 2, ctx); } else { slong i, e; e = exp[0]; ca_one(poly + e, ctx); for (i = e - 1; i >= 0; i--) { ca_mul(poly + i, poly + i + 1, xs, ctx); ca_mul_si(poly + i, poly + i, -(i + 1), ctx); ca_div_ui(poly + i, poly + i, e - i, ctx); } } } else if (n == 2 && exp[0] == 1 && exp[1] == 1) { ca_mul(poly, xs + 0, xs + 1, ctx); ca_add(poly + 1, xs + 0, xs + 1, ctx); ca_neg(poly + 1, poly + 1, ctx); ca_one(poly + 2, ctx); } else { slong i, m, deg_left, deg_right; ca_ptr tmp; /* todo: balance degrees */ m = (n + 1) / 2; deg_left = deg_right = 0; for (i = 0; i < m; i++) deg_left += exp[i]; for (i = m; i < n; i++) deg_right += exp[i]; tmp = _ca_vec_init(deg_left + deg_right + 2, ctx); _ca_poly_set_roots(tmp, xs, exp, m, ctx); _ca_poly_set_roots(tmp + deg_left + 1, xs + m, exp + m, n - m, ctx); _ca_poly_mul(poly, tmp, deg_left + 1, tmp + deg_left + 1, deg_right + 1, ctx); _ca_vec_clear(tmp, deg_left + deg_right + 2, ctx); } } void ca_poly_set_roots(ca_poly_t poly, ca_vec_t roots, const ulong * exp, ca_ctx_t ctx) { slong i, deg, len; len = ca_vec_length(roots, ctx); /* todo: check for overflow? */ deg = 0; for (i = 0; i < len; i++) deg += exp[i]; ca_poly_fit_length(poly, deg + 1, ctx); _ca_poly_set_roots(poly->coeffs, roots->entries, exp, len, ctx); _ca_poly_set_length(poly, deg + 1, ctx); } calcium-0.4.1/ca_poly/set_si.c000066400000000000000000000012511407704557200162230ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_set_si(ca_poly_t poly, slong x, ca_ctx_t ctx) { if (x == 0) { ca_poly_zero(poly, ctx); } else { ca_poly_fit_length(poly, 1, ctx); ca_set_si(poly->coeffs, x, ctx); _ca_poly_set_length(poly, 1, ctx); } } calcium-0.4.1/ca_poly/shift_left.c000066400000000000000000000024141407704557200170660ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_shift_left(ca_ptr res, ca_srcptr poly, slong len, slong n, ca_ctx_t ctx) { slong i; /* Copy in reverse to avoid writing over unshifted coefficients */ if (res != poly) { for (i = len; i--; ) ca_set(res + n + i, poly + i, ctx); } else { for (i = len; i--; ) ca_swap(res + n + i, res + i, ctx); } for (i = 0; i < n; i++) ca_zero(res + i, ctx); } void ca_poly_shift_left(ca_poly_t res, const ca_poly_t poly, slong n, ca_ctx_t ctx) { if (n == 0) { ca_poly_set(res, poly, ctx); return; } if (poly->length == 0) { ca_poly_zero(res, ctx); return; } ca_poly_fit_length(res, poly->length + n, ctx); _ca_poly_shift_left(res->coeffs, poly->coeffs, poly->length, n, ctx); _ca_poly_set_length(res, poly->length + n, ctx); } calcium-0.4.1/ca_poly/shift_right.c000066400000000000000000000023541407704557200172540ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_shift_right(ca_ptr res, ca_srcptr poly, slong len, slong n, ca_ctx_t ctx) { slong i; /* Copy in forward order to avoid writing over unshifted coefficients */ if (res != poly) { for (i = 0; i < len - n; i++) ca_set(res + i, poly + n + i, ctx); } else { for (i = 0; i < len - n; i++) ca_swap(res + i, res + n + i, ctx); } } void ca_poly_shift_right(ca_poly_t res, const ca_poly_t poly, slong n, ca_ctx_t ctx) { if (n == 0) { ca_poly_set(res, poly, ctx); return; } if (poly->length <= n) { ca_poly_zero(res, ctx); return; } ca_poly_fit_length(res, poly->length - n, ctx); _ca_poly_shift_right(res->coeffs, poly->coeffs, poly->length, n, ctx); _ca_poly_set_length(res, poly->length - n, ctx); } calcium-0.4.1/ca_poly/squarefree_part.c000066400000000000000000000022271407704557200201310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int ca_poly_squarefree_part(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx) { ca_poly_t t; int success; if (poly->length <= 1) { ca_poly_one(res, ctx); return 1; } if (poly->length == 2) return ca_poly_make_monic(res, poly, ctx); ca_poly_init(t, ctx); ca_poly_derivative(t, poly, ctx); success = ca_poly_gcd(t, poly, t, ctx); if (success) { if (t->length == 1) /* gcd = 1 */ { success = ca_poly_make_monic(res, poly, ctx); } else { success = ca_poly_div(res, poly, t, ctx); if (success) success = ca_poly_make_monic(res, res, ctx); } } ca_poly_clear(t, ctx); return success; } calcium-0.4.1/ca_poly/sub.c000066400000000000000000000022521407704557200155300ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_sub(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) { slong i, min = FLINT_MIN(len1, len2); for (i = 0; i < min; i++) ca_sub(res + i, poly1 + i, poly2 + i, ctx); for (i = min; i < len1; i++) ca_set(res + i, poly1 + i, ctx); for (i = min; i < len2; i++) ca_neg(res + i, poly2 + i, ctx); } void ca_poly_sub(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) { slong max = FLINT_MAX(poly1->length, poly2->length); ca_poly_fit_length(res, max, ctx); _ca_poly_sub(res->coeffs, poly1->coeffs, poly1->length, poly2->coeffs, poly2->length, ctx); _ca_poly_set_length(res, max, ctx); _ca_poly_normalise(res, ctx); } calcium-0.4.1/ca_poly/test/000077500000000000000000000000001407704557200155515ustar00rootroot00000000000000calcium-0.4.1/ca_poly/test/t-atan_series.c000066400000000000000000000026511407704557200204570ustar00rootroot00000000000000/* Copyright (C) 2020, 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("atan_series...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, B; slong n1; ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); ca_poly_randtest_rational(A, state, 10, 10, ctx); n1 = n_randint(state, 10); if (n_randint(state, 2)) { ca_poly_atan_series(B, A, n1, ctx); } else { ca_poly_set(B, A, ctx); ca_poly_atan_series(B, B, n1, ctx); } if (!(A->length == 0 || ca_check_is_zero(A->coeffs, ctx) != T_FALSE)) { /* ... todo: test something here ... */ } ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-compose.c000066400000000000000000000045671407704557200176370ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("compose...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 300 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t F, G, FG; ca_poly_t x, Fx, Gx, FxGx, FGx; /* Test F(x) + G(x) = (F + G)(x) */ ca_ctx_init(ctx); ca_poly_init(F, ctx); ca_poly_init(G, ctx); ca_poly_init(FG, ctx); ca_poly_init(x, ctx); ca_poly_init(Fx, ctx); ca_poly_init(Gx, ctx); ca_poly_init(FxGx, ctx); ca_poly_init(FGx, ctx); ca_poly_randtest(F, state, 6, 1, 5, ctx); ca_poly_randtest(G, state, 6, 1, 5, ctx); ca_poly_randtest(x, state, 4, 1, 5, ctx); ca_poly_randtest(Fx, state, 4, 1, 5, ctx); ca_poly_add(FG, F, G, ctx); ca_poly_compose(Fx, F, x, ctx); ca_poly_set(Gx, x, ctx); /* test aliasing */ ca_poly_compose(Gx, G, Gx, ctx); ca_poly_add(FxGx, Fx, Gx, ctx); ca_poly_compose(FGx, FG, x, ctx); if (ca_poly_check_equal(FxGx, FGx, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("F = "); ca_poly_print(F, ctx); flint_printf("\n"); flint_printf("G = "); ca_poly_print(G, ctx); flint_printf("\n"); flint_printf("x = "); ca_poly_print(x, ctx); flint_printf("\n"); flint_printf("FxGx = "); ca_poly_print(FxGx, ctx); flint_printf("\n"); flint_printf("FGx = "); ca_poly_print(FGx, ctx); flint_printf("\n"); flint_abort(); } ca_poly_clear(F, ctx); ca_poly_clear(G, ctx); ca_poly_clear(FG, ctx); ca_poly_clear(x, ctx); ca_poly_clear(Fx, ctx); ca_poly_clear(Gx, ctx); ca_poly_clear(FxGx, ctx); ca_poly_clear(FGx, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-compose_divconquer.c000066400000000000000000000046431407704557200220710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("compose_divconquer...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 300 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t F, G, FG; ca_poly_t x, Fx, Gx, FxGx, FGx; /* Test F(x) + G(x) = (F + G)(x) */ ca_ctx_init(ctx); ca_poly_init(F, ctx); ca_poly_init(G, ctx); ca_poly_init(FG, ctx); ca_poly_init(x, ctx); ca_poly_init(Fx, ctx); ca_poly_init(Gx, ctx); ca_poly_init(FxGx, ctx); ca_poly_init(FGx, ctx); ca_poly_randtest(F, state, 6, 1, 5, ctx); ca_poly_randtest(G, state, 6, 1, 5, ctx); ca_poly_randtest(x, state, 4, 1, 5, ctx); ca_poly_randtest(Fx, state, 4, 1, 5, ctx); ca_poly_add(FG, F, G, ctx); ca_poly_compose_divconquer(Fx, F, x, ctx); ca_poly_set(Gx, x, ctx); /* test aliasing */ ca_poly_compose_divconquer(Gx, G, Gx, ctx); ca_poly_add(FxGx, Fx, Gx, ctx); ca_poly_compose_divconquer(FGx, FG, x, ctx); if (ca_poly_check_equal(FxGx, FGx, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("F = "); ca_poly_print(F, ctx); flint_printf("\n"); flint_printf("G = "); ca_poly_print(G, ctx); flint_printf("\n"); flint_printf("x = "); ca_poly_print(x, ctx); flint_printf("\n"); flint_printf("FxGx = "); ca_poly_print(FxGx, ctx); flint_printf("\n"); flint_printf("FGx = "); ca_poly_print(FGx, ctx); flint_printf("\n"); flint_abort(); } ca_poly_clear(F, ctx); ca_poly_clear(G, ctx); ca_poly_clear(FG, ctx); ca_poly_clear(x, ctx); ca_poly_clear(Fx, ctx); ca_poly_clear(Gx, ctx); ca_poly_clear(FxGx, ctx); ca_poly_clear(FGx, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-compose_horner.c000066400000000000000000000046231407704557200212050ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("compose_horner...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 300 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t F, G, FG; ca_poly_t x, Fx, Gx, FxGx, FGx; /* Test F(x) + G(x) = (F + G)(x) */ ca_ctx_init(ctx); ca_poly_init(F, ctx); ca_poly_init(G, ctx); ca_poly_init(FG, ctx); ca_poly_init(x, ctx); ca_poly_init(Fx, ctx); ca_poly_init(Gx, ctx); ca_poly_init(FxGx, ctx); ca_poly_init(FGx, ctx); ca_poly_randtest(F, state, 6, 1, 5, ctx); ca_poly_randtest(G, state, 6, 1, 5, ctx); ca_poly_randtest(x, state, 4, 1, 5, ctx); ca_poly_randtest(Fx, state, 4, 1, 5, ctx); ca_poly_add(FG, F, G, ctx); ca_poly_compose_horner(Fx, F, x, ctx); ca_poly_set(Gx, x, ctx); /* test aliasing */ ca_poly_compose_horner(Gx, G, Gx, ctx); ca_poly_add(FxGx, Fx, Gx, ctx); ca_poly_compose_horner(FGx, FG, x, ctx); if (ca_poly_check_equal(FxGx, FGx, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("F = "); ca_poly_print(F, ctx); flint_printf("\n"); flint_printf("G = "); ca_poly_print(G, ctx); flint_printf("\n"); flint_printf("x = "); ca_poly_print(x, ctx); flint_printf("\n"); flint_printf("FxGx = "); ca_poly_print(FxGx, ctx); flint_printf("\n"); flint_printf("FGx = "); ca_poly_print(FGx, ctx); flint_printf("\n"); flint_abort(); } ca_poly_clear(F, ctx); ca_poly_clear(G, ctx); ca_poly_clear(FG, ctx); ca_poly_clear(x, ctx); ca_poly_clear(Fx, ctx); ca_poly_clear(Gx, ctx); ca_poly_clear(FxGx, ctx); ca_poly_clear(FGx, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-div_series.c000066400000000000000000000101571407704557200203160ustar00rootroot00000000000000/* Copyright (C) 2020, 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_randtest_same_nf(ca_poly_t res, flint_rand_t state, const ca_t x, slong len, slong bits, slong den_bits, ca_ctx_t ctx) { slong i; fmpz_t t; ca_poly_fit_length(res, len, ctx); for (i = 0; i < len; i++) ca_randtest_same_nf(res->coeffs + i, state, x, bits, 1, ctx); _ca_poly_set_length(res, len, ctx); _ca_poly_normalise(res, ctx); fmpz_init(t); fmpz_randtest_not_zero(t, state, den_bits); ca_poly_div_fmpz(res, res, t, ctx); fmpz_clear(t); } /* todo */ void ca_poly_truncate(ca_poly_t poly, slong newlen, ca_ctx_t ctx) { if (poly->length > newlen) { slong i; for (i = newlen; i < poly->length; i++) ca_zero(poly->coeffs + i, ctx); poly->length = newlen; _ca_poly_normalise(poly, ctx); } } int main() { slong iter; flint_rand_t state; flint_printf("div_series...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, B, AB, ABB, An; slong n1; /* Test (A / B) * B == A */ ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); ca_poly_init(AB, ctx); ca_poly_init(ABB, ctx); ca_poly_init(An, ctx); if (n_randint(state, 2)) { if (n_randint(state, 2)) ca_poly_randtest_rational(A, state, 10, 10, ctx); else ca_poly_randtest(A, state, 4, 2, 10, ctx); if (n_randint(state, 2)) ca_poly_randtest_rational(B, state, 10, 10, ctx); else ca_poly_randtest(B, state, 4, 2, 10, ctx); n1 = n_randint(state, 6); } else { qqbar_t t; ca_t x; qqbar_init(t); ca_init(x, ctx); qqbar_randtest(t, state, 8, 10); ca_set_qqbar(x, t, ctx); ca_poly_randtest_same_nf(A, state, x, 1 + n_randint(state, 20), 2 + n_randint(state, 100), 2 + n_randint(state, 100), ctx); ca_poly_randtest_same_nf(B, state, x, 1 + n_randint(state, 20), 2 + n_randint(state, 100), 2 + n_randint(state, 100), ctx); n1 = n_randint(state, 50); qqbar_clear(t); ca_clear(x, ctx); } ca_poly_randtest(AB, state, 4, 2, 10, ctx); if (n_randint(state, 2)) { ca_poly_set(AB, A, ctx); ca_poly_div_series(AB, AB, B, n1, ctx); } else if (n_randint(state, 2)) { ca_poly_set(AB, B, ctx); ca_poly_div_series(AB, A, AB, n1, ctx); } else { ca_poly_div_series(AB, A, B, n1, ctx); } ca_poly_mullow(ABB, AB, B, n1, ctx); ca_poly_set(An, A, ctx); ca_poly_truncate(An, n1, ctx); if (!(B->length == 0 || ca_check_is_zero(B->coeffs, ctx) != T_FALSE)) { if (ca_poly_check_equal(ABB, An, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("AB = "); ca_poly_print(AB, ctx); flint_printf("\n"); flint_printf("ABB = "); ca_poly_print(ABB, ctx); flint_printf("\n"); flint_abort(); } } ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); ca_poly_clear(AB, ctx); ca_poly_clear(ABB, ctx); ca_poly_clear(An, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-divrem.c000066400000000000000000000055211407704557200174470ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("divrem..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, B, Q, R, T; int success; /* Test A = Q*B + R */ ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); ca_poly_init(Q, ctx); ca_poly_init(R, ctx); ca_poly_init(T, ctx); ca_poly_randtest(A, state, 4, 2, 10, ctx); ca_poly_randtest(B, state, 4, 2, 10, ctx); ca_poly_randtest(Q, state, 4, 2, 10, ctx); ca_poly_randtest(R, state, 4, 2, 10, ctx); ca_poly_randtest(T, state, 4, 2, 10, ctx); /* test aliasing */ switch (n_randint(state, 5)) { case 0: ca_poly_set(Q, A, ctx); success = ca_poly_divrem(Q, R, Q, B, ctx); break; case 1: ca_poly_set(R, A, ctx); success = ca_poly_divrem(Q, R, R, B, ctx); break; case 2: ca_poly_set(Q, B, ctx); success = ca_poly_divrem(Q, R, A, Q, ctx); break; case 3: ca_poly_set(R, B, ctx); success = ca_poly_divrem(Q, R, A, R, ctx); break; default: success = ca_poly_divrem(Q, R, A, B, ctx); break; } if (success) { ca_poly_mul(T, Q, B, ctx); ca_poly_add(T, T, R, ctx); if (ca_poly_check_equal(A, T, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("Q = "); ca_poly_print(Q, ctx); flint_printf("\n"); flint_printf("R = "); ca_poly_print(R, ctx); flint_printf("\n"); flint_printf("T = "); ca_poly_print(T, ctx); flint_printf("\n"); flint_abort(); } } ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); ca_poly_clear(Q, ctx); ca_poly_clear(R, ctx); ca_poly_clear(T, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-evaluate.c000066400000000000000000000044261407704557200177720ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("evaluate...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 300 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t F, G, FG; ca_t x, Fx, Gx, FxGx, FGx; /* Test F(x) + G(x) = (F + G)(x) */ ca_ctx_init(ctx); ca_poly_init(F, ctx); ca_poly_init(G, ctx); ca_poly_init(FG, ctx); ca_init(x, ctx); ca_init(Fx, ctx); ca_init(Gx, ctx); ca_init(FxGx, ctx); ca_init(FGx, ctx); ca_poly_randtest(F, state, 8, 1, 5, ctx); ca_poly_randtest(G, state, 8, 1, 5, ctx); ca_randtest(x, state, 1, 5, ctx); ca_randtest(Fx, state, 1, 5, ctx); ca_poly_add(FG, F, G, ctx); ca_poly_evaluate(Fx, F, x, ctx); ca_set(Gx, x, ctx); /* test aliasing */ ca_poly_evaluate(Gx, G, Gx, ctx); ca_add(FxGx, Fx, Gx, ctx); ca_poly_evaluate(FGx, FG, x, ctx); if (ca_check_equal(FxGx, FGx, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("F = "); ca_poly_print(F, ctx); flint_printf("\n"); flint_printf("G = "); ca_poly_print(G, ctx); flint_printf("\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n"); flint_printf("FxGx = "); ca_print(FxGx, ctx); flint_printf("\n"); flint_printf("FGx = "); ca_print(FGx, ctx); flint_printf("\n"); flint_abort(); } ca_poly_clear(F, ctx); ca_poly_clear(G, ctx); ca_poly_clear(FG, ctx); ca_clear(x, ctx); ca_clear(Fx, ctx); ca_clear(Gx, ctx); ca_clear(FxGx, ctx); ca_clear(FGx, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-evaluate_horner.c000066400000000000000000000044621407704557200213470ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("evaluate_horner...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 300 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t F, G, FG; ca_t x, Fx, Gx, FxGx, FGx; /* Test F(x) + G(x) = (F + G)(x) */ ca_ctx_init(ctx); ca_poly_init(F, ctx); ca_poly_init(G, ctx); ca_poly_init(FG, ctx); ca_init(x, ctx); ca_init(Fx, ctx); ca_init(Gx, ctx); ca_init(FxGx, ctx); ca_init(FGx, ctx); ca_poly_randtest(F, state, 8, 1, 5, ctx); ca_poly_randtest(G, state, 8, 1, 5, ctx); ca_randtest(x, state, 1, 5, ctx); ca_randtest(Fx, state, 1, 5, ctx); ca_poly_add(FG, F, G, ctx); ca_poly_evaluate_horner(Fx, F, x, ctx); ca_set(Gx, x, ctx); /* test aliasing */ ca_poly_evaluate_horner(Gx, G, Gx, ctx); ca_add(FxGx, Fx, Gx, ctx); ca_poly_evaluate_horner(FGx, FG, x, ctx); if (ca_check_equal(FxGx, FGx, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("F = "); ca_poly_print(F, ctx); flint_printf("\n"); flint_printf("G = "); ca_poly_print(G, ctx); flint_printf("\n"); flint_printf("x = "); ca_print(x, ctx); flint_printf("\n"); flint_printf("FxGx = "); ca_print(FxGx, ctx); flint_printf("\n"); flint_printf("FGx = "); ca_print(FGx, ctx); flint_printf("\n"); flint_abort(); } ca_poly_clear(F, ctx); ca_poly_clear(G, ctx); ca_poly_clear(FG, ctx); ca_clear(x, ctx); ca_clear(Fx, ctx); ca_clear(Gx, ctx); ca_clear(FxGx, ctx); ca_clear(FGx, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-exp_series.c000066400000000000000000000100571407704557200203270ustar00rootroot00000000000000/* Copyright (C) 2020, 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_randtest_same_nf(ca_poly_t res, flint_rand_t state, const ca_t x, slong len, slong bits, slong den_bits, ca_ctx_t ctx) { slong i; fmpz_t t; ca_poly_fit_length(res, len, ctx); for (i = 0; i < len; i++) ca_randtest_same_nf(res->coeffs + i, state, x, bits, 1, ctx); _ca_poly_set_length(res, len, ctx); _ca_poly_normalise(res, ctx); fmpz_init(t); fmpz_randtest_not_zero(t, state, den_bits); ca_poly_div_fmpz(res, res, t, ctx); fmpz_clear(t); } /* todo */ void ca_poly_truncate(ca_poly_t poly, slong newlen, ca_ctx_t ctx) { if (poly->length > newlen) { slong i; for (i = newlen; i < poly->length; i++) ca_zero(poly->coeffs + i, ctx); poly->length = newlen; _ca_poly_normalise(poly, ctx); } } int main() { slong iter; flint_rand_t state; flint_printf("exp_series...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, B, AB, expA, expB, expAB, expAexpB; slong n1, n2, n3; /* Test exp(A)*exp(B) = exp(A+B) */ ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); ca_poly_init(AB, ctx); ca_poly_init(expA, ctx); ca_poly_init(expB, ctx); ca_poly_init(expAB, ctx); ca_poly_init(expAexpB, ctx); if (n_randint(state, 2)) { ca_poly_randtest(A, state, 4, 2, 10, ctx); ca_poly_randtest(B, state, 4, 2, 10, ctx); n1 = n_randint(state, 6); n2 = n_randint(state, 6); n3 = n_randint(state, 6); } else { qqbar_t t; ca_t x; qqbar_init(t); ca_init(x, ctx); qqbar_randtest(t, state, 8, 10); ca_set_qqbar(x, t, ctx); ca_poly_randtest_same_nf(A, state, x, 1 + n_randint(state, 20), 2 + n_randint(state, 100), 2 + n_randint(state, 100), ctx); ca_poly_randtest_same_nf(B, state, x, 1 + n_randint(state, 20), 2 + n_randint(state, 100), 2 + n_randint(state, 100), ctx); n1 = n_randint(state, 50); n2 = n_randint(state, 50); n3 = n_randint(state, 50); qqbar_clear(t); ca_clear(x, ctx); } ca_poly_randtest(expA, state, 4, 2, 10, ctx); ca_poly_randtest(expB, state, 4, 2, 10, ctx); ca_poly_randtest(expAB, state, 4, 2, 10, ctx); ca_poly_add(AB, A, B, ctx); ca_poly_exp_series(expA, A, n1, ctx); ca_poly_exp_series(expB, B, n2, ctx); ca_poly_exp_series(expAB, AB, n3, ctx); ca_poly_mullow(expAexpB, expA, expB, FLINT_MIN(FLINT_MIN(n1, n2), n3), ctx); ca_poly_truncate(expAB, FLINT_MIN(FLINT_MIN(n1, n2), n3), ctx); if (ca_poly_check_equal(expAB, expAexpB, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("expAexpB = "); ca_poly_print(expAexpB, ctx); flint_printf("\n"); flint_printf("expAB = "); ca_poly_print(expAB, ctx); flint_printf("\n"); flint_abort(); } ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); ca_poly_clear(AB, ctx); ca_poly_clear(expA, ctx); ca_poly_clear(expB, ctx); ca_poly_clear(expAB, ctx); ca_poly_clear(expAexpB, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-factor_squarefree.c000066400000000000000000000103721407704557200216610ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("factor_squarefree..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, B, C, P, Q, G1, G2, G3; ca_t c; ca_poly_vec_t F; int success; ulong ea, eb, ec, maxexp; ulong * exp; slong i, j; ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); ca_poly_init(C, ctx); ca_poly_init(G1, ctx); ca_poly_init(G2, ctx); ca_poly_init(G3, ctx); ca_poly_init(P, ctx); ca_poly_init(Q, ctx); ca_poly_vec_init(F, 0, ctx); ca_init(c, ctx); ea = 1 + n_randint(state, 2); eb = 1 + n_randint(state, 2); ec = 1 + n_randint(state, 4); do { if (n_randint(state, 2) == 0) { ca_poly_randtest(A, state, 2, 0, 3, ctx); ca_poly_randtest_rational(B, state, 2, 3, ctx); ca_poly_randtest_rational(C, state, 2, 3, ctx); } else { ca_poly_randtest_rational(A, state, 4, 3, ctx); ca_poly_randtest_rational(B, state, 4, 3, ctx); ca_poly_randtest_rational(C, state, 4, 3, ctx); } } while (A->length < 2 || B->length < 2 || C->length < 2 || !ca_poly_gcd(G1, A, B, ctx) || (ca_poly_check_is_one(G1, ctx) != T_TRUE) || !ca_poly_gcd(G2, A, C, ctx) || (ca_poly_check_is_one(G2, ctx) != T_TRUE) || !ca_poly_gcd(G3, B, C, ctx) || (ca_poly_check_is_one(G3, ctx) != T_TRUE)); ca_poly_one(P, ctx); for (i = 0; i < ea; i++) ca_poly_mul(P, P, A, ctx); for (i = 0; i < eb; i++) ca_poly_mul(P, P, B, ctx); for (i = 0; i < ec; i++) ca_poly_mul(P, P, C, ctx); exp = flint_malloc(sizeof(ulong) * P->length); success = ca_poly_factor_squarefree(c, F, exp, P, ctx); if (success) { ca_poly_one(Q, ctx); for (i = 0; i < F->length; i++) for (j = 0; j < exp[i]; j++) ca_poly_mul(Q, Q, F->entries + i, ctx); ca_poly_mul_ca(Q, Q, c, ctx); maxexp = 0; for (i = 0; i < F->length; i++) maxexp = FLINT_MAX(maxexp, exp[i]); if (ca_poly_check_equal(P, Q, ctx) == T_FALSE || maxexp < FLINT_MAX(FLINT_MAX(ea, eb), ec)) { flint_printf("FAIL (product)\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("ea = %wu\n\n", ea); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("eb = %wu\n\n", eb); flint_printf("C = "); ca_poly_print(C, ctx); flint_printf("\n"); flint_printf("ec = %wu\n\n", ec); flint_printf("P = "); ca_poly_print(P, ctx); flint_printf("\n"); flint_printf("Q = "); ca_poly_print(Q, ctx); flint_printf("\n"); for (i = 0; i < F->length; i++) { flint_printf("Multiplicity %wu: ", exp[i]); ca_poly_print(F->entries + i, ctx); } flint_abort(); } } flint_free(exp); ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); ca_poly_clear(C, ctx); ca_poly_clear(G1, ctx); ca_poly_clear(G2, ctx); ca_poly_clear(G3, ctx); ca_poly_clear(P, ctx); ca_poly_clear(Q, ctx); ca_poly_vec_clear(F, ctx); ca_clear(c, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-gcd.c000066400000000000000000000107111407704557200167130ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("gcd..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, B, C, AC, BC, MC, G; int success; ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); ca_poly_init(C, ctx); ca_poly_init(AC, ctx); ca_poly_init(BC, ctx); ca_poly_init(MC, ctx); ca_poly_init(G, ctx); if (n_randint(state, 10) != 0) { do { ca_poly_randtest_rational(A, state, 4, 10, ctx); ca_poly_randtest_rational(B, state, 4, 10, ctx); success = ca_poly_gcd(G, A, B, ctx); } while (!success || ca_poly_check_is_one(G, ctx) != T_TRUE); ca_poly_randtest(C, state, 4, 2, 10, ctx); } else { do { ca_poly_randtest(A, state, 3, 2, 10, ctx); ca_poly_randtest(B, state, 3, 2, 10, ctx); success = ca_poly_gcd(G, A, B, ctx); } while (!success || ca_poly_check_is_one(G, ctx) != T_TRUE); ca_poly_randtest_rational(C, state, 3, 10, ctx); } ca_poly_mul(AC, A, C, ctx); ca_poly_mul(BC, B, C, ctx); switch (n_randint(state, 3)) { case 0: ca_poly_set(G, AC, ctx); success = ca_poly_gcd(G, G, BC, ctx); break; case 1: ca_poly_set(G, BC, ctx); success = ca_poly_gcd(G, AC, G, ctx); break; default: success = ca_poly_gcd(G, AC, BC, ctx); break; } if (success) { ca_poly_make_monic(MC, C, ctx); if (ca_poly_check_equal(MC, G, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("C = "); ca_poly_print(C, ctx); flint_printf("\n"); flint_printf("G = "); ca_poly_print(G, ctx); flint_printf("\n"); flint_abort(); } } ca_poly_randtest(A, state, 3, 2, 10, ctx); success = ca_poly_gcd(G, A, A, ctx); if (success) { ca_poly_make_monic(B, A, ctx); if (ca_poly_check_equal(G, B, ctx) == T_FALSE) { flint_printf("FAIL (self)\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("G = "); ca_poly_print(G, ctx); flint_printf("\n"); flint_abort(); } } /* compare with gcd_euclidean */ ca_poly_randtest(A, state, 3, 0, 5, ctx); ca_poly_randtest_rational(B, state, 3, 5, ctx); ca_poly_randtest_rational(C, state, 3, 5, ctx); ca_poly_mul(A, A, C, ctx); ca_poly_mul(B, B, C, ctx); if (ca_poly_gcd(G, A, B, ctx) && ca_poly_gcd_euclidean(C, A, B, ctx) && ca_poly_check_equal(G, C, ctx) == T_FALSE) { flint_printf("FAIL (2)\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("G = "); ca_poly_print(G, ctx); flint_printf("\n"); flint_printf("C = "); ca_poly_print(C, ctx); flint_printf("\n"); flint_abort(); } ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); ca_poly_clear(C, ctx); ca_poly_clear(AC, ctx); ca_poly_clear(BC, ctx); ca_poly_clear(MC, ctx); ca_poly_clear(G, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-gcd_euclidean.c000066400000000000000000000073501407704557200207310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("gcd_euclidean..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, B, C, AC, BC, MC, G; int success; ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); ca_poly_init(C, ctx); ca_poly_init(AC, ctx); ca_poly_init(BC, ctx); ca_poly_init(MC, ctx); ca_poly_init(G, ctx); if (n_randint(state, 10) != 0) { do { ca_poly_randtest_rational(A, state, 4, 10, ctx); ca_poly_randtest_rational(B, state, 4, 10, ctx); success = ca_poly_gcd_euclidean(G, A, B, ctx); } while (!success || ca_poly_check_is_one(G, ctx) != T_TRUE); ca_poly_randtest(C, state, 4, 2, 10, ctx); } else { do { ca_poly_randtest(A, state, 3, 2, 10, ctx); ca_poly_randtest(B, state, 3, 2, 10, ctx); success = ca_poly_gcd_euclidean(G, A, B, ctx); } while (!success || ca_poly_check_is_one(G, ctx) != T_TRUE); ca_poly_randtest_rational(C, state, 3, 10, ctx); } ca_poly_mul(AC, A, C, ctx); ca_poly_mul(BC, B, C, ctx); switch (n_randint(state, 3)) { case 0: ca_poly_set(G, AC, ctx); success = ca_poly_gcd_euclidean(G, G, BC, ctx); break; case 1: ca_poly_set(G, BC, ctx); success = ca_poly_gcd_euclidean(G, AC, G, ctx); break; default: success = ca_poly_gcd_euclidean(G, AC, BC, ctx); break; } if (success) { ca_poly_make_monic(MC, C, ctx); if (ca_poly_check_equal(MC, G, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("C = "); ca_poly_print(C, ctx); flint_printf("\n"); flint_printf("G = "); ca_poly_print(G, ctx); flint_printf("\n"); flint_abort(); } } ca_poly_randtest(A, state, 3, 2, 10, ctx); success = ca_poly_gcd_euclidean(G, A, A, ctx); if (success) { ca_poly_make_monic(B, A, ctx); if (ca_poly_check_equal(G, B, ctx) == T_FALSE) { flint_printf("FAIL (self)\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("G = "); ca_poly_print(G, ctx); flint_printf("\n"); flint_abort(); } } ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); ca_poly_clear(C, ctx); ca_poly_clear(AC, ctx); ca_poly_clear(BC, ctx); ca_poly_clear(MC, ctx); ca_poly_clear(G, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-inv_series.c000066400000000000000000000065741407704557200203400ustar00rootroot00000000000000/* Copyright (C) 2020, 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_randtest_same_nf(ca_poly_t res, flint_rand_t state, const ca_t x, slong len, slong bits, slong den_bits, ca_ctx_t ctx) { slong i; fmpz_t t; ca_poly_fit_length(res, len, ctx); for (i = 0; i < len; i++) ca_randtest_same_nf(res->coeffs + i, state, x, bits, 1, ctx); _ca_poly_set_length(res, len, ctx); _ca_poly_normalise(res, ctx); fmpz_init(t); fmpz_randtest_not_zero(t, state, den_bits); ca_poly_div_fmpz(res, res, t, ctx); fmpz_clear(t); } /* todo */ void ca_poly_truncate(ca_poly_t poly, slong newlen, ca_ctx_t ctx) { if (poly->length > newlen) { slong i; for (i = newlen; i < poly->length; i++) ca_zero(poly->coeffs + i, ctx); poly->length = newlen; _ca_poly_normalise(poly, ctx); } } int main() { slong iter; flint_rand_t state; flint_printf("inv_series...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, B, AB, one; slong n1; /* Test inv(A) * A == 1 */ ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); ca_poly_init(AB, ctx); ca_poly_init(one, ctx); if (n_randint(state, 2)) { ca_poly_randtest(A, state, 4, 2, 10, ctx); n1 = n_randint(state, 6); } else { qqbar_t t; ca_t x; qqbar_init(t); ca_init(x, ctx); qqbar_randtest(t, state, 8, 10); ca_set_qqbar(x, t, ctx); ca_poly_randtest_same_nf(A, state, x, 1 + n_randint(state, 20), 2 + n_randint(state, 100), 2 + n_randint(state, 100), ctx); n1 = n_randint(state, 50); qqbar_clear(t); ca_clear(x, ctx); } ca_poly_randtest(B, state, 4, 2, 10, ctx); if (n_randint(state, 2)) { ca_poly_set(B, A, ctx); ca_poly_inv_series(B, B, n1, ctx); } else { ca_poly_inv_series(B, A, n1, ctx); } ca_poly_mullow(AB, A, B, n1, ctx); ca_poly_one(one, ctx); ca_poly_truncate(one, n1, ctx); if (!(A->length == 0 || ca_check_is_zero(A->coeffs, ctx) != T_FALSE)) { if (ca_poly_check_equal(AB, one, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("AB = "); ca_poly_print(AB, ctx); flint_printf("\n"); flint_abort(); } } ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); ca_poly_clear(AB, ctx); ca_poly_clear(one, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-log_series.c000066400000000000000000000046341407704557200203200ustar00rootroot00000000000000/* Copyright (C) 2020, 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" /* todo */ void ca_poly_truncate(ca_poly_t poly, slong newlen, ca_ctx_t ctx) { if (poly->length > newlen) { slong i; for (i = newlen; i < poly->length; i++) ca_zero(poly->coeffs + i, ctx); poly->length = newlen; _ca_poly_normalise(poly, ctx); } } int main() { slong iter; flint_rand_t state; flint_printf("log_series...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, B, C, D; slong n1; /* Test exp(log(A)) == A */ ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); ca_poly_init(C, ctx); ca_poly_init(D, ctx); ca_poly_randtest_rational(A, state, 10, 10, ctx); n1 = n_randint(state, 10); if (n_randint(state, 2)) { ca_poly_log_series(B, A, n1, ctx); } else { ca_poly_set(B, A, ctx); ca_poly_log_series(B, B, n1, ctx); } ca_poly_exp_series(C, B, n1, ctx); ca_poly_set(D, A, ctx); ca_poly_truncate(D, n1, ctx); if (!(A->length == 0 || ca_check_is_zero(A->coeffs, ctx) != T_FALSE)) { if (ca_poly_check_equal(C, D, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("C = "); ca_poly_print(C, ctx); flint_printf("\n"); flint_printf("D = "); ca_poly_print(D, ctx); flint_printf("\n"); flint_abort(); } } ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); ca_poly_clear(C, ctx); ca_poly_clear(D, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-mul.c000066400000000000000000000103221407704557200167510ustar00rootroot00000000000000/* Copyright (C) 2020, 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_randtest_same_nf(ca_poly_t res, flint_rand_t state, const ca_t x, slong len, slong bits, slong den_bits, ca_ctx_t ctx) { slong i; fmpz_t t; ca_poly_fit_length(res, len, ctx); for (i = 0; i < len; i++) ca_randtest_same_nf(res->coeffs + i, state, x, bits, 1, ctx); _ca_poly_set_length(res, len, ctx); _ca_poly_normalise(res, ctx); fmpz_init(t); fmpz_randtest_not_zero(t, state, den_bits); ca_poly_div_fmpz(res, res, t, ctx); fmpz_clear(t); } int main() { slong iter; flint_rand_t state; flint_printf("mul...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 300 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, B, C, ABC, AB, AC, ABAC; /* Test A*(B+C) = A*B + A*C */ ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); ca_poly_init(C, ctx); ca_poly_init(ABC, ctx); ca_poly_init(AB, ctx); ca_poly_init(AC, ctx); ca_poly_init(ABAC, ctx); if (n_randint(state, 2)) { ca_poly_randtest(A, state, 4, 2, 10, ctx); ca_poly_randtest(B, state, 4, 2, 10, ctx); ca_poly_randtest(C, state, 4, 2, 10, ctx); } else { qqbar_t t; ca_t x; qqbar_init(t); ca_init(x, ctx); qqbar_randtest(t, state, 8, 10); ca_set_qqbar(x, t, ctx); ca_poly_randtest_same_nf(A, state, x, 1 + n_randint(state, 20), 2 + n_randint(state, 100), 2 + n_randint(state, 100), ctx); ca_poly_randtest_same_nf(B, state, x, 1 + n_randint(state, 20), 2 + n_randint(state, 100), 2 + n_randint(state, 100), ctx); ca_poly_randtest_same_nf(C, state, x, 1 + n_randint(state, 20), 2 + n_randint(state, 100), 2 + n_randint(state, 100), ctx); qqbar_clear(t); ca_clear(x, ctx); } ca_poly_randtest(ABC, state, 4, 2, 10, ctx); ca_poly_randtest(AB, state, 4, 2, 10, ctx); ca_poly_randtest(AC, state, 4, 2, 10, ctx); ca_poly_randtest(ABAC, state, 4, 2, 10, ctx); ca_poly_add(ABC, B, C, ctx); if (n_randint(state, 2)) ca_poly_mul(ABC, A, ABC, ctx); else ca_poly_mul(ABC, ABC, A, ctx); ca_poly_mul(AB, A, B, ctx); ca_poly_mul(AC, A, C, ctx); ca_poly_add(ABAC, AB, AC, ctx); if (ca_poly_check_equal(ABC, ABAC, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("C = "); ca_poly_print(C, ctx); flint_printf("\n"); flint_printf("ABC = "); ca_poly_print(ABC, ctx); flint_printf("\n"); flint_printf("ABAC = "); ca_poly_print(ABAC, ctx); flint_printf("\n"); flint_abort(); } /* Test A^2 = A * A */ ca_poly_set(B, A, ctx); ca_poly_mul(AB, A, B, ctx); ca_poly_mul(AC, A, A, ctx); if (ca_poly_check_equal(AB, AC, ctx) == T_FALSE) { flint_printf("FAIL (squaring)\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("AB = "); ca_poly_print(AB, ctx); flint_printf("\n"); flint_printf("AC = "); ca_poly_print(AC, ctx); flint_printf("\n"); flint_abort(); } ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); ca_poly_clear(C, ctx); ca_poly_clear(ABC, ctx); ca_poly_clear(AB, ctx); ca_poly_clear(AC, ctx); ca_poly_clear(ABAC, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-pow_ui.c000066400000000000000000000040461407704557200174640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("pow_ui...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, An, Am, AnAm, Anm; ulong n, m; /* Test A^n * A^m = A^(n+m) */ ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(An, ctx); ca_poly_init(Am, ctx); ca_poly_init(AnAm, ctx); ca_poly_init(Anm, ctx); ca_poly_randtest(A, state, 5, 1, 5, ctx); n = n_randint(state, 5); m = n_randint(state, 5); ca_poly_pow_ui(An, A, n, ctx); ca_poly_set(Am, A, ctx); ca_poly_pow_ui(Am, Am, m, ctx); ca_poly_mul(AnAm, An, Am, ctx); ca_poly_pow_ui(Anm, A, n + m, ctx); if (ca_poly_check_equal(AnAm, Anm, ctx) == T_FALSE) { flint_printf("FAIL\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("An = "); ca_poly_print(An, ctx); flint_printf("\n"); flint_printf("Am = "); ca_poly_print(Am, ctx); flint_printf("\n"); flint_printf("AnAm = "); ca_poly_print(AnAm, ctx); flint_printf("\n"); flint_printf("Anm = "); ca_poly_print(Anm, ctx); flint_printf("\n"); flint_abort(); } ca_poly_clear(A, ctx); ca_poly_clear(An, ctx); ca_poly_clear(Am, ctx); ca_poly_clear(AnAm, ctx); ca_poly_clear(Anm, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-roots.c000066400000000000000000000055441407704557200173340ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("roots...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_vec_t R; ca_poly_t A, B; ulong * exp; ca_ctx_init(ctx); ca_vec_init(R, 0, ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); if (n_randint(state, 10) != 0) { ca_poly_randtest(A, state, 5, 1, 10, ctx); } else { ca_poly_randtest(A, state, 3, 0, 5, ctx); ca_poly_randtest_rational(B, state, 3, 5, ctx); ca_poly_mul(A, A, B, ctx); if (n_randint(state, 2)) ca_poly_mul(A, A, B, ctx); if (n_randint(state, 2)) ca_poly_mul(A, A, B, ctx); } exp = flint_malloc(sizeof(ulong) * A->length); if (ca_poly_roots(R, exp, A, ctx)) { ca_poly_set_roots(B, R, exp, ctx); if (A->length) ca_poly_mul_ca(B, B, A->coeffs + A->length - 1, ctx); if (ca_poly_check_equal(A, B, ctx) == T_FALSE) { slong i; flint_printf("FAIL\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("R = "); ca_vec_print(R, ctx); flint_printf("\n"); for (i = 0; i < R->length; i++) flint_printf("e[%wd] = %wu\n", i, exp[i]); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_abort(); } if (0) { printf("=================================================================\n\n"); printf("EQUAL: "); truth_print(ca_poly_check_equal(A, B, ctx)); printf("\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n\n"); flint_printf("R = "); ca_vec_print(R, ctx); flint_printf("\n\n"); ca_poly_sub(B, A, B, ctx); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n\n"); } } ca_vec_clear(R, ctx); ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); flint_free(exp); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/test/t-squarefree_part.c000066400000000000000000000041041407704557200213450ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" int main() { slong iter; flint_rand_t state; flint_printf("squarefree_part..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { ca_ctx_t ctx; ca_poly_t A, B, C; ca_t c; ca_poly_vec_t F; ulong * exp; slong i; ca_ctx_init(ctx); ca_poly_init(A, ctx); ca_poly_init(B, ctx); ca_poly_init(C, ctx); ca_poly_vec_init(F, 0, ctx); ca_init(c, ctx); ca_poly_randtest(A, state, 5, 1, 5, ctx); exp = flint_malloc(sizeof(ulong) * A->length); if (ca_poly_factor_squarefree(c, F, exp, A, ctx)) { if (ca_poly_squarefree_part(B, A, ctx)) { ca_poly_one(C, ctx); for (i = 0; i < F->length; i++) ca_poly_mul(C, C, F->entries + i, ctx); if (ca_poly_check_equal(B, C, ctx) == T_FALSE) { flint_printf("FAIL (product)\n\n"); flint_printf("A = "); ca_poly_print(A, ctx); flint_printf("\n"); flint_printf("B = "); ca_poly_print(B, ctx); flint_printf("\n"); flint_printf("C = "); ca_poly_print(C, ctx); flint_printf("\n"); flint_abort(); } } } flint_free(exp); ca_poly_clear(A, ctx); ca_poly_clear(B, ctx); ca_poly_clear(C, ctx); ca_poly_vec_clear(F, ctx); ca_clear(c, ctx); ca_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/ca_poly/transfer.c000066400000000000000000000016221407704557200165630ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_transfer(ca_poly_t res, ca_ctx_t res_ctx, const ca_poly_t src, ca_ctx_t src_ctx) { slong i, len; if (res_ctx == src_ctx) { ca_poly_set(res, src, res_ctx); } else { len = src->length; ca_poly_fit_length(res, len, res_ctx); _ca_poly_set_length(res, len, res_ctx); for (i = 0; i < src->length; i++) ca_transfer(res->coeffs + i, res_ctx, src->coeffs + i, src_ctx); _ca_poly_normalise(res, res_ctx); } } calcium-0.4.1/ca_poly/vec_append.c000066400000000000000000000011521407704557200170410ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void ca_poly_vec_append(ca_poly_vec_t vec, const ca_poly_t f, ca_ctx_t ctx) { _ca_poly_vec_fit_length(vec, vec->length + 1, ctx); ca_poly_set(vec->entries + vec->length, f, ctx); vec->length++; } calcium-0.4.1/ca_poly/vec_clear.c000066400000000000000000000013421407704557200166610ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_vec_clear(ca_poly_struct * v, slong n, ca_ctx_t ctx) { slong i; for (i = 0; i < n; i++) ca_poly_clear(v + i, ctx); flint_free(v); } void ca_poly_vec_clear(ca_poly_vec_t vec, ca_ctx_t ctx) { if (vec->entries != NULL) { _ca_poly_vec_clear(vec->entries, vec->alloc, ctx); } } calcium-0.4.1/ca_poly/vec_init.c000066400000000000000000000016721407704557200165440ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" ca_poly_struct * _ca_poly_vec_init(slong n, ca_ctx_t ctx) { slong i; ca_poly_struct * v = (ca_poly_struct *) flint_malloc(sizeof(ca_poly_struct) * n); for (i = 0; i < n; i++) ca_poly_init(v + i, ctx); return v; } void ca_poly_vec_init(ca_poly_vec_t res, slong len, ca_ctx_t ctx) { if (len == 0) { res->entries = NULL; res->length = 0; res->alloc = 0; } else { res->entries = _ca_poly_vec_init(len, ctx); res->length = len; res->alloc = len; } } calcium-0.4.1/ca_poly/vec_set_length.c000066400000000000000000000023371407704557200177340ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_poly.h" void _ca_poly_vec_fit_length(ca_poly_vec_t vec, slong len, ca_ctx_t ctx) { if (len > vec->alloc) { slong i; if (len < 2 * vec->alloc) len = 2 * vec->alloc; vec->entries = flint_realloc(vec->entries, len * sizeof(ca_poly_struct)); for (i = vec->alloc; i < len; i++) ca_poly_init(vec->entries + i, ctx); vec->alloc = len; } } void ca_poly_vec_set_length(ca_poly_vec_t vec, slong len, ca_ctx_t ctx) { slong i; if (vec->length > len) { for (i = len; i < vec->length; i++) ca_poly_zero(vec->entries + i, ctx); } else if (vec->length < len) { _ca_poly_vec_fit_length(vec, len, ctx); for (i = vec->length; i < len; i++) ca_poly_zero(vec->entries + i, ctx); } vec->length = len; } calcium-0.4.1/ca_vec.h000066400000000000000000000117531407704557200145440ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef CA_VEC_H #define CA_VEC_H #ifdef CA_VEC_INLINES_C #define CA_VEC_INLINE #else #define CA_VEC_INLINE static __inline__ #endif #include #include "flint/flint.h" #include "flint/fmpz_poly.h" #include "flint/fmpq_poly.h" #include "arb_poly.h" #include "acb_poly.h" #include "antic/nf.h" #include "antic/nf_elem.h" #include "ca.h" #ifdef __cplusplus extern "C" { #endif /* Vector object */ typedef struct { ca_ptr entries; slong length; slong alloc; } ca_vec_struct; typedef ca_vec_struct ca_vec_t[1]; #define ca_vec_entry(vec, i) ((vec)->entries + (i)) CA_VEC_INLINE ca_ptr ca_vec_entry_ptr(ca_vec_t vec, slong i) { return ca_vec_entry(vec, i); } /* Memory management */ ca_ptr _ca_vec_init(slong len, ca_ctx_t ctx); void ca_vec_init(ca_vec_t vec, slong len, ca_ctx_t ctx); void _ca_vec_clear(ca_ptr v, slong len, ca_ctx_t ctx); void ca_vec_clear(ca_vec_t vec, ca_ctx_t ctx); void _ca_vec_swap(ca_ptr vec1, ca_ptr vec2, slong len, ca_ctx_t ctx); CA_VEC_INLINE void ca_vec_swap(ca_vec_t vec1, ca_vec_t vec2, ca_ctx_t ctx) { ca_vec_struct t = *vec1; *vec1 = *vec2; *vec2 = t; } /* Length */ CA_VEC_INLINE slong ca_vec_length(const ca_vec_t vec, ca_ctx_t ctx) { return vec->length; } void _ca_vec_fit_length(ca_vec_t vec, slong len, ca_ctx_t ctx); void ca_vec_set_length(ca_vec_t res, slong len, ca_ctx_t ctx); /* Assignment */ void _ca_vec_set(ca_ptr res, ca_srcptr src, slong len, ca_ctx_t ctx); void ca_vec_set(ca_vec_t res, const ca_vec_t src, ca_ctx_t ctx); /* Special vectors */ void _ca_vec_zero(ca_ptr res, slong len, ca_ctx_t ctx); void ca_vec_zero(ca_vec_t res, slong len, ca_ctx_t ctx); CA_VEC_INLINE void _ca_vec_unknown(ca_ptr vec, slong len, ca_ctx_t ctx) { slong i; for (i = 0; i < len; i++) ca_unknown(vec + i, ctx); } CA_VEC_INLINE void _ca_vec_undefined(ca_ptr vec, slong len, ca_ctx_t ctx) { slong i; for (i = 0; i < len; i++) ca_undefined(vec + i, ctx); } /* Input and output */ void ca_vec_print(const ca_vec_t vec, ca_ctx_t ctx); void ca_vec_printn(const ca_vec_t vec, slong digits, ca_ctx_t ctx); /* List operations */ CA_VEC_INLINE void ca_vec_append(ca_vec_t vec, const ca_t f, ca_ctx_t ctx) { _ca_vec_fit_length(vec, vec->length + 1, ctx); ca_set(vec->entries + vec->length, f, ctx); vec->length++; } /* Arithmetic */ void _ca_vec_neg(ca_ptr res, ca_srcptr src, slong len, ca_ctx_t ctx); void ca_vec_neg(ca_vec_t res, const ca_vec_t src, ca_ctx_t ctx); void _ca_vec_add(ca_ptr res, ca_srcptr vec1, ca_srcptr vec2, slong len, ca_ctx_t ctx); void _ca_vec_sub(ca_ptr res, ca_srcptr vec1, ca_srcptr vec2, slong len, ca_ctx_t ctx); void _ca_vec_scalar_mul_ca(ca_ptr res, ca_srcptr src, slong len, const ca_t c, ca_ctx_t ctx); void _ca_vec_scalar_div_ca(ca_ptr res, ca_srcptr src, slong len, const ca_t c, ca_ctx_t ctx); void _ca_vec_scalar_addmul_ca(ca_ptr res, ca_srcptr vec, slong len, const ca_t c, ca_ctx_t ctx); void _ca_vec_scalar_submul_ca(ca_ptr res, ca_srcptr vec, slong len, const ca_t c, ca_ctx_t ctx); /* Comparisons and predicates */ truth_t _ca_vec_check_is_zero(ca_srcptr vec, slong len, ca_ctx_t ctx); /* Internal representation */ CA_VEC_INLINE int _ca_vec_is_fmpq_vec(ca_srcptr vec, slong len, ca_ctx_t ctx) { slong i; for (i = 0; i < len; i++) if (!CA_IS_QQ(vec + i, ctx)) return 0; return 1; } CA_VEC_INLINE int _ca_vec_fmpq_vec_is_fmpz_vec(ca_srcptr vec, slong len, ca_ctx_t ctx) { slong i; for (i = 0; i < len; i++) if (!fmpz_is_one(CA_FMPQ_DENREF(vec + i))) return 0; return 1; } CA_VEC_INLINE void _ca_vec_fmpq_vec_get_fmpz_vec_den(fmpz * c, fmpz_t den, ca_srcptr vec, slong len, ca_ctx_t ctx) { slong i; fmpz_one(den); if (_ca_vec_fmpq_vec_is_fmpz_vec(vec, len, ctx)) { for (i = 0; i < len; i++) fmpz_set(c + i, CA_FMPQ_NUMREF(vec + i)); } else { for (i = 0; i < len; i++) fmpz_lcm(den, den, CA_FMPQ_DENREF(vec + i)); for (i = 0; i < len; i++) { fmpz_divexact(c + i, den, CA_FMPQ_DENREF(vec + i)); fmpz_mul(c + i, c + i, CA_FMPQ_NUMREF(vec + i)); } } } CA_VEC_INLINE void _ca_vec_set_fmpz_vec_div_fmpz(ca_ptr res, const fmpz * v, const fmpz_t den, slong len, ca_ctx_t ctx) { slong i; if (fmpz_is_one(den)) { for (i = 0; i < len; i++) ca_set_fmpz(res + i, v + i, ctx); } else { for (i = 0; i < len; i++) { ca_set_fmpz(res + i, v + i, ctx); /* todo: optimize */ ca_div_fmpz(res + i, res + i, den, ctx); } } } #ifdef __cplusplus } #endif #endif calcium-0.4.1/ca_vec/000077500000000000000000000000001407704557200143645ustar00rootroot00000000000000calcium-0.4.1/ca_vec/add.c000066400000000000000000000011211407704557200152530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_add(ca_ptr res, ca_srcptr vec1, ca_srcptr vec2, slong len, ca_ctx_t ctx) { slong i; for (i = 0; i < len; i++) ca_add(res + i, vec1 + i, vec2 + i, ctx); } calcium-0.4.1/ca_vec/check_is_zero.c000066400000000000000000000015351407704557200173430ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" truth_t _ca_vec_check_is_zero(ca_srcptr vec, slong len, ca_ctx_t ctx) { slong i; int have_unknown; truth_t is_zero; have_unknown = 0; for (i = 0; i < len; i++) { is_zero = ca_check_is_zero(vec + i, ctx); if (is_zero == T_FALSE) return T_FALSE; if (is_zero == T_UNKNOWN) have_unknown = 1; } if (have_unknown) return T_UNKNOWN; else return T_TRUE; } calcium-0.4.1/ca_vec/clear.c000066400000000000000000000012761407704557200156240ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_clear(ca_ptr v, slong n, ca_ctx_t ctx) { slong i; for (i = 0; i < n; i++) ca_clear(v + i, ctx); flint_free(v); } void ca_vec_clear(ca_vec_t vec, ca_ctx_t ctx) { if (vec->entries != NULL) { _ca_vec_clear(vec->entries, vec->alloc, ctx); } } calcium-0.4.1/ca_vec/init.c000066400000000000000000000015751407704557200155030ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" ca_ptr _ca_vec_init(slong n, ca_ctx_t ctx) { slong i; ca_ptr v = (ca_ptr) flint_malloc(sizeof(ca_struct) * n); for (i = 0; i < n; i++) ca_init(v + i, ctx); return v; } void ca_vec_init(ca_vec_t res, slong len, ca_ctx_t ctx) { if (len == 0) { res->entries = NULL; res->length = 0; res->alloc = 0; } else { res->entries = _ca_vec_init(len, ctx); res->length = len; res->alloc = len; } } calcium-0.4.1/ca_vec/inlines.c000066400000000000000000000006621407704557200161750ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #define CA_VEC_INLINES_C #include "ca_vec.h" calcium-0.4.1/ca_vec/neg.c000066400000000000000000000014671407704557200153110ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_neg(ca_ptr res, ca_srcptr src, slong len, ca_ctx_t ctx) { slong i; for (i = 0; i < len; i++) ca_neg(res + i, src + i, ctx); } void ca_vec_neg(ca_vec_t res, const ca_vec_t src, ca_ctx_t ctx) { if (res != src) { ca_vec_set_length(res, ca_vec_length(src, ctx), ctx); _ca_vec_neg(ca_vec_entry(res, 0), ca_vec_entry(src, 0), ca_vec_length(res, ctx), ctx); } } calcium-0.4.1/ca_vec/print.c000066400000000000000000000020161407704557200156630ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void ca_vec_print(const ca_vec_t vec, ca_ctx_t ctx) { slong i, len; len = vec->length; flint_printf("ca_vec of length %wd:\n", len); for (i = 0; i < len; i++) { flint_printf(" "); ca_print(vec->entries + i, ctx); flint_printf("\n"); } flint_printf("\n"); } void ca_vec_printn(const ca_vec_t vec, slong digits, ca_ctx_t ctx) { slong len, i; len = vec->length; flint_printf("["); for (i = 0; i < len; i++) { ca_printn(vec->entries + i, digits, ctx); if (i < len - 1) flint_printf(", "); } flint_printf("]\n"); } calcium-0.4.1/ca_vec/scalar_addmul_ca.c000066400000000000000000000013631407704557200177710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_scalar_addmul_ca(ca_ptr res, ca_srcptr vec, slong len, const ca_t c, ca_ctx_t ctx) { slong i; ca_t t; if (len > 0) { ca_init(t, ctx); for (i = 0; i < len; i++) { ca_mul(t, vec + i, c, ctx); ca_add(res + i, res + i, t, ctx); } ca_clear(t, ctx); } } calcium-0.4.1/ca_vec/scalar_div_ca.c000066400000000000000000000013241407704557200173020ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_scalar_div_ca(ca_ptr res, ca_srcptr src, slong len, const ca_t c, ca_ctx_t ctx) { slong i; if (len > 0) { ca_t t; ca_init(t, ctx); ca_inv(t, c, ctx); for (i = 0; i < len; i++) ca_mul(res + i, src + i, t, ctx); ca_clear(t, ctx); } } calcium-0.4.1/ca_vec/scalar_mul_ca.c000066400000000000000000000011201407704557200173070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_scalar_mul_ca(ca_ptr res, ca_srcptr src, slong len, const ca_t c, ca_ctx_t ctx) { slong i; for (i = 0; i < len; i++) ca_mul(res + i, src + i, c, ctx); } calcium-0.4.1/ca_vec/scalar_submul_ca.c000066400000000000000000000013631407704557200200320ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_scalar_submul_ca(ca_ptr res, ca_srcptr vec, slong len, const ca_t c, ca_ctx_t ctx) { slong i; ca_t t; if (len > 0) { ca_init(t, ctx); for (i = 0; i < len; i++) { ca_mul(t, vec + i, c, ctx); ca_sub(res + i, res + i, t, ctx); } ca_clear(t, ctx); } } calcium-0.4.1/ca_vec/set.c000066400000000000000000000014671407704557200153330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_set(ca_ptr res, ca_srcptr src, slong len, ca_ctx_t ctx) { slong i; for (i = 0; i < len; i++) ca_set(res + i, src + i, ctx); } void ca_vec_set(ca_vec_t res, const ca_vec_t src, ca_ctx_t ctx) { if (res != src) { ca_vec_set_length(res, ca_vec_length(src, ctx), ctx); _ca_vec_set(ca_vec_entry(res, 0), ca_vec_entry(src, 0), ca_vec_length(res, ctx), ctx); } } calcium-0.4.1/ca_vec/set_length.c000066400000000000000000000022751407704557200166720ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_fit_length(ca_vec_t vec, slong len, ca_ctx_t ctx) { if (len > vec->alloc) { slong i; if (len < 2 * vec->alloc) len = 2 * vec->alloc; vec->entries = flint_realloc(vec->entries, len * sizeof(ca_struct)); for (i = vec->alloc; i < len; i++) ca_init(ca_vec_entry(vec, i), ctx); vec->alloc = len; } } void ca_vec_set_length(ca_vec_t vec, slong len, ca_ctx_t ctx) { slong i; if (vec->length > len) { for (i = len; i < vec->length; i++) ca_zero(ca_vec_entry(vec, i), ctx); } else if (vec->length < len) { _ca_vec_fit_length(vec, len, ctx); for (i = vec->length; i < len; i++) ca_zero(ca_vec_entry(vec, i), ctx); } vec->length = len; } calcium-0.4.1/ca_vec/sub.c000066400000000000000000000011211407704557200153140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_sub(ca_ptr res, ca_srcptr vec1, ca_srcptr vec2, slong len, ca_ctx_t ctx) { slong i; for (i = 0; i < len; i++) ca_sub(res + i, vec1 + i, vec2 + i, ctx); } calcium-0.4.1/ca_vec/swap.c000066400000000000000000000010701407704557200155000ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_swap(ca_ptr vec1, ca_ptr vec2, slong len, ca_ctx_t ctx) { slong i; for (i = 0; i < len; i++) ca_swap(vec1 + i, vec2 + i, ctx); } calcium-0.4.1/ca_vec/zero.c000066400000000000000000000013101407704557200155020ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "ca_vec.h" void _ca_vec_zero(ca_ptr res, slong len, ca_ctx_t ctx) { slong i; for (i = 0; i < len; i++) ca_zero(res + i, ctx); } void ca_vec_zero(ca_vec_t res, slong len, ca_ctx_t ctx) { ca_vec_set_length(res, len, ctx); _ca_vec_zero(ca_vec_entry(res, 0), ca_vec_length(res, ctx), ctx); } calcium-0.4.1/calcium.h000066400000000000000000000070131407704557200147330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef CALCIUM_H #define CALCIUM_H #ifdef CALCIUM_INLINES_C #define CALCIUM_INLINE #else #define CALCIUM_INLINE static __inline__ #endif #include #include "flint/flint.h" #include "flint/fmpz.h" #include "acb.h" #ifdef __cplusplus extern "C" { #endif /* Global library definitions */ const char * calcium_version(void); #define __CALCIUM_VERSION 0 #define __CALCIUM_VERSION_MINOR 4 #define __CALCIUM_VERSION_PATCHLEVEL 1 #define CALCIUM_VERSION "0.4.0" #define __CALCIUM_RELEASE (__CALCIUM_VERSION * 10000 + \ __CALCIUM_VERSION_MINOR * 100 + \ __CALCIUM_VERSION_PATCHLEVEL) double calcium_test_multiplier(void); /* Input and output */ typedef struct { FILE * fp; char * s; slong len; slong alloc; } calcium_stream_struct; typedef calcium_stream_struct calcium_stream_t[1]; CALCIUM_INLINE void calcium_stream_init_file(calcium_stream_t out, FILE * fp) { out->fp = fp; out->s = NULL; } CALCIUM_INLINE void calcium_stream_init_str(calcium_stream_t out) { out->fp = NULL; out->s = flint_malloc(16); out->s[0] = '\0'; out->len = 0; out->alloc = 16; } void calcium_write(calcium_stream_t out, const char * s); void calcium_write_si(calcium_stream_t out, slong x); void calcium_write_fmpz(calcium_stream_t out, const fmpz_t c); void calcium_write_acb(calcium_stream_t out, const acb_t z, slong digits, ulong flags); CALCIUM_INLINE void calcium_write_free(calcium_stream_t out, char * s) { calcium_write(out, s); flint_free(s); } /* Triple-valued logic */ typedef enum { T_TRUE, T_FALSE, T_UNKNOWN } truth_t; CALCIUM_INLINE void truth_print(truth_t t) { if (t == T_TRUE) flint_printf("T_TRUE"); if (t == T_FALSE) flint_printf("T_FALSE"); if (t == T_UNKNOWN) flint_printf("T_UNKNOWN"); } /* IDs for builtin mathematical functions and constants */ typedef enum { /* Special case for representing qqbar instances */ CA_QQBar, /* Arithmetic */ CA_Neg, CA_Add, CA_Sub, CA_Mul, CA_Div, /* Roots */ CA_Sqrt, CA_Cbrt, CA_Root, /* Complex parts */ CA_Floor, CA_Ceil, CA_Abs, CA_Sign, CA_Re, CA_Im, CA_Arg, CA_Conjugate, /* Elementary constants */ CA_Pi, /* Elementary functions */ CA_Sin, CA_Cos, CA_Exp, CA_Log, CA_Pow, CA_Tan, CA_Cot, CA_Cosh, CA_Sinh, CA_Tanh, CA_Coth, CA_Atan, CA_Acos, CA_Asin, CA_Acot, CA_Atanh, CA_Acosh, CA_Asinh, CA_Acoth, /* Euler's constant */ CA_Euler, /* Gamma and related functions */ CA_Gamma, CA_LogGamma, CA_Psi, CA_Erf, CA_Erfc, CA_Erfi, CA_RiemannZeta, CA_HurwitzZeta, CA_FUNC_CODE_LENGTH } calcium_func_code; const char * calcium_func_name(calcium_func_code func); /* Flint extras */ /* slower alternative: fmpz_fdiv_ui(x 1000000007) */ CALCIUM_INLINE ulong calcium_fmpz_hash(const fmpz_t x) { if (!COEFF_IS_MPZ(*x)) return *x; else { __mpz_struct * z = COEFF_TO_PTR(*x); return (z->_mp_size > 0) ? z->_mp_d[0] : -z->_mp_d[0]; } } #ifdef __cplusplus } #endif #endif calcium-0.4.1/calcium/000077500000000000000000000000001407704557200145615ustar00rootroot00000000000000calcium-0.4.1/calcium/func_name.c000066400000000000000000000043671407704557200166720ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" const char * calcium_func_name(calcium_func_code func) { switch (func) { /* Arithmetic */ case CA_Neg: return "Neg"; case CA_Add: return "Add"; case CA_Sub: return "Sub"; case CA_Mul: return "Mul"; case CA_Div: return "Div"; /* Roots */ case CA_Sqrt: return "Sqrt"; case CA_Cbrt: return "Cbrt"; case CA_Root: return "Root"; /* Complex parts */ case CA_Floor: return "Floor"; case CA_Ceil: return "Ceil"; case CA_Abs: return "Abs"; case CA_Sign: return "Sign"; case CA_Re: return "Re"; case CA_Im: return "Im"; case CA_Arg: return "Arg"; case CA_Conjugate: return "Conjugate"; /* Elementary constants */ case CA_Pi: return "Pi"; /* Elementary functions */ case CA_Exp: return "Exp"; case CA_Log: return "Log"; case CA_Pow: return "Pow"; case CA_Cos: return "Cos"; case CA_Sin: return "Sin"; case CA_Tan: return "Tan"; case CA_Cosh: return "Cosh"; case CA_Sinh: return "Sinh"; case CA_Tanh: return "Tanh"; case CA_Atan: return "Atan"; case CA_Acos: return "Acos"; case CA_Asin: return "Asin"; case CA_Atanh: return "Atanh"; case CA_Acosh: return "Acosh"; case CA_Asinh: return "Asinh"; /* Euler's constant */ case CA_Euler: return "Euler"; /* Gamma and related functions */ case CA_Gamma: return "Gamma"; case CA_LogGamma: return "LogGamma"; case CA_Psi: return "Psi"; case CA_Erf: return "Erf"; case CA_Erfc: return "Erfc"; case CA_Erfi: return "Erfi"; case CA_RiemannZeta: return "RiemannZeta"; case CA_HurwitzZeta: return "HurwitzZeta"; default: return ""; } } calcium-0.4.1/calcium/test_multiplier.c000066400000000000000000000017211407704557200201530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include #include "calcium.h" double _calcium_test_multiplier = -1.0; double calcium_test_multiplier() { if (_calcium_test_multiplier == -1.0) { const char * s = getenv("CALCIUM_TEST_MULTIPLIER"); if (s == NULL) { _calcium_test_multiplier = 1.0; } else { _calcium_test_multiplier = strtod(s, NULL); if (!(_calcium_test_multiplier >= 0.0 && _calcium_test_multiplier <= 1000.0)) _calcium_test_multiplier = 1.0; } } return _calcium_test_multiplier; } calcium-0.4.1/calcium/version.c000066400000000000000000000010411407704557200164060ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" const char * __calcium_version_string = CALCIUM_VERSION; const char * calcium_version(void) { return __calcium_version_string; } calcium-0.4.1/calcium/write.c000066400000000000000000000016471407704557200160670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include #include "calcium.h" void calcium_write(calcium_stream_t out, const char * s) { if (out->fp != NULL) { flint_fprintf(out->fp, s); } else { slong len, alloc; len = strlen(s); alloc = out->len + len + 1; if (alloc > out->alloc) { alloc = FLINT_MAX(alloc, out->alloc * 2); out->s = flint_realloc(out->s, alloc); out->alloc = alloc; } memcpy(out->s + out->len, s, len + 1); out->len += len; } } calcium-0.4.1/calcium/write_acb.c000066400000000000000000000057111407704557200166700ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include #include "calcium.h" /* todo: this will be obsolete with a new arb release */ static char * arb_get_str2(const arb_t x, slong digits, ulong flags) { char * s; if (!arb_is_finite(x) && (flags & ARB_STR_NO_RADIUS)) { s = flint_malloc(4); strcpy(s, "???"); return s; } s = arb_get_str(x, digits, flags); if ((flags & ARB_STR_NO_RADIUS) && (s[0] == '[')) { slong i, j; fmpz_t e; fmpz_init(e); for (i = 1; s[i] != '\0'; i++) { if (s[i] == 'e') { for (j = i + 1; s[j] != '\0'; j++) { if (s[j] == ']') { s[j] = '\0'; break; } } if (s[i + 1] == '+') fmpz_set_str(e, s + i + 2, 10); else fmpz_set_str(e, s + i + 1, 10); fmpz_add_ui(e, e, 1); s[0] = '0'; s[1] = 'e'; if (fmpz_sgn(e) < 0) { fmpz_get_str(s + 2, 10, e); } else { s[2] = '+'; fmpz_get_str(s + 3, 10, e); } break; } } fmpz_clear(e); } return s; } void calcium_write_arb(calcium_stream_t out, const arb_t x, slong digits, ulong flags) { calcium_write_free(out, arb_get_str2(x, digits, flags)); } void calcium_write_acb(calcium_stream_t out, const acb_t z, slong digits, ulong flags) { if (arb_is_zero(acb_imagref(z))) { calcium_write_free(out, arb_get_str2(acb_realref(z), digits, flags)); } else if (arb_is_zero(acb_realref(z))) { calcium_write_free(out, arb_get_str2(acb_imagref(z), digits, flags)); calcium_write(out, "*I"); } else { calcium_write_free(out, arb_get_str2(acb_realref(z), digits, flags)); if ((arb_is_exact(acb_imagref(z)) || (flags & ARB_STR_NO_RADIUS)) && arf_sgn(arb_midref(acb_imagref(z))) < 0) { arb_t t; arb_init(t); arb_neg(t, acb_imagref(z)); calcium_write(out, " - "); calcium_write_free(out, arb_get_str2(t, digits, flags)); arb_clear(t); } else { calcium_write(out, " + "); calcium_write_free(out, arb_get_str2(acb_imagref(z), digits, flags)); } calcium_write(out, "*I"); } } calcium-0.4.1/calcium/write_si.c000066400000000000000000000013641407704557200165560ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" void calcium_write_si(calcium_stream_t out, slong x) { if (out->fp != NULL) { flint_fprintf(out->fp, "%wd", x); } else { char tmp[22]; if (sizeof(slong) == sizeof(long)) sprintf(tmp, "%ld", x); else flint_sprintf(tmp, "%wd", x); calcium_write(out, tmp); } } calcium-0.4.1/configure000077500000000000000000000371361407704557200150650ustar00rootroot00000000000000#!/bin/sh # (C) 2007, Robert Bradshaw, William Hart, William Stein, Michael Abshoff # (C) 2011, William Hart # (C) 2012, William Hart, Jean-Pierre Flori, Thomas DuBuisson # (C) 2012, Jan Engelhardt # ./configure --disable-static --with-flint=/home/fredrik/src/flint2 --with-arb=/home/fredrik/src/arb --with-antic=/home/fredrik/src/antic # soname version # # calcium => soname # 0.0.1 => 0.0.1 CALCIUM_MAJOR=0 CALCIUM_MINOR=4 CALCIUM_PATCH=1 PREFIX="/usr/local" GMP_DIR="/usr/local" MPFR_DIR="/usr/local" FLINT_DIR="/usr/local" ARB_DIR="/usr/local" ANTIC_DIR="/usr/local" NTL_DIR="/usr/local" GC_DIR="/usr/local" BLAS_DIR="/usr/local" SHARED=1 STATIC=1 TLS=1 PTHREAD=1 WANT_TLS=0 ASSERT=0 BUILD= EXTENSIONS= EXT_MODS= EXTRA_BUILD= usage() { echo "Usage: ./configure " echo " where may be" echo " -h display usage information" echo " where may be:" echo " --prefix= Specify path to installation location (default: /usr/local)" echo " --with-mpir= Specify location of MPIR (default: /usr/local)" echo " --with-gmp= Specify location of GMP (default: /usr/local)" echo " --with-mpfr= Specify location of MPFR (default: /usr/local)" echo " --with-flint= Specify location of FLINT (default: /usr/local)" echo " --with-arb= Specify location of ARB (default: /usr/local)" echo " --with-antic= Specify location of ANTIC (default: /usr/local)" echo " --build=arch-os Specify architecture/OS combination rather than use values from uname -m/-s" echo " --enable-shared Build a shared library (default)" echo " --disable-shared Do not build a shared library" echo " --enable-static Build a static library (default)" echo " --disable-static Do not build a static library" echo " --single Faster [non-reentrant if tls or pthread not used] version of library (default)" echo " --reentrant Build fully reentrant [with or without tls, with pthread] version of library" echo " --with-gc= GC safe build with path to gc" echo " --enable-pthread Use pthread (default)" echo " --disable-pthread Do not use pthread" echo " --enable-tls Use thread-local storage (default)" echo " --disable-tls Do not use thread-local storage" echo " --enable-assert Enable use of asserts (use for debug builds only)" echo " --disable-assert Disable use of asserts (default)" echo " --enable-cxx Enable C++ wrapper tests" echo " --disable-cxx Disable C++ wrapper tests (default)" echo " CC= Use the C compiler with the given name (default: gcc)" echo " CXX= Use the C++ compiler with the given name (default: g++)" echo " AR= Use the AR library builder with the given name (default: ar)" echo " CFLAGS= Pass the given flags to the compiler" echo " ABI=[32|64] Tell the compiler to use given ABI (default: empty)" } absolute_path(){ dirlist="$1" retval="" for dir in $dirlist; do case $dir in /*) dir=$dir;; *) dir=$PWD/$dir;; esac retval=$retval" "$dir done echo $retval } while [ "$1" != "" ]; do PARAM=`echo $1 | sed 's/=.*//'` VALUE=`echo $1 | sed 's/[^=]*//; s/=//'` case "$PARAM" in -h|--help) usage exit 0 ;; --with-mpir|--with-gmp) GMP_DIR=$(absolute_path "$VALUE") ;; --with-mpfr) MPFR_DIR=$(absolute_path "$VALUE") ;; --with-flint) FLINT_DIR=$(absolute_path "$VALUE") ;; --with-arb) ARB_DIR=$(absolute_path "$VALUE") ;; --with-antic) ANTIC_DIR=$(absolute_path "$VALUE") ;; --build) BUILD="$VALUE" ;; --prefix) PREFIX=$VALUE ;; --enable-shared) SHARED=1 ;; --disable-shared) SHARED=0 ;; --enable-static) STATIC=1 ;; --disable-static) STATIC=0 ;; --single) REENTRANT=0 ;; --reentrant) REENTRANT=1 ;; --enable-pthread) PTHREAD=1 ;; --disable-pthread) PTHREAD=0 ;; --enable-tls) TLS=1 WANT_TLS=1;; --disable-tls) TLS=0 ;; --enable-assert) ASSERT=1 ;; --disable-assert) ASSERT=0 ;; AR) AR="$VALUE" ;; CC) CC="$VALUE" ;; CXX) CXX="$VALUE" ;; CFLAGS) CFLAGS="$VALUE" ;; ABI) ABI="$VALUE" ;; *) usage exit 1 ;; esac shift done #find dependencies LIBS="m" if [ -d "${GMP_DIR}/lib" ]; then GMP_LIB_DIR="${GMP_DIR}/lib" GMP_INC_DIR="${GMP_DIR}/include" elif [ -d "${GMP_DIR}/lib64" ]; then GMP_LIB_DIR="${GMP_DIR}/lib64" GMP_INC_DIR="${GMP_DIR}/include" elif [ -d "${GMP_DIR}/.libs" ]; then GMP_LIB_DIR="${GMP_DIR}/.libs" GMP_INC_DIR="${GMP_DIR}" else echo "Invalid GMP directory" exit 1 fi LIB_DIRS="${LIB_DIRS} ${GMP_LIB_DIR}" INC_DIRS="${INC_DIRS} ${GMP_INC_DIR}" LIBS="${LIBS} gmp" if [ -d "${MPFR_DIR}/lib" ]; then MPFR_LIB_DIR="${MPFR_DIR}/lib" MPFR_INC_DIR="${MPFR_DIR}/include" elif [ -d "${MPFR_DIR}/lib64" ]; then MPFR_LIB_DIR="${MPFR_DIR}/lib64" MPFR_INC_DIR="${MPFR_DIR}/include" elif [ -d "${MPFR_DIR}/.libs" ]; then MPFR_LIB_DIR="${MPFR_DIR}/.libs" MPFR_INC_DIR="${MPFR_DIR}" elif [ -d "${MPFR_DIR}/src/.libs" ]; then MPFR_LIB_DIR="${MPFR_DIR}/src/.libs" MPFR_INC_DIR="${MPFR_DIR}/src" else echo "Invalid MPFR directory" exit 1 fi LIB_DIRS="${LIB_DIRS} ${MPFR_LIB_DIR}" INC_DIRS="${INC_DIRS} ${MPFR_INC_DIR}" LIBS="${LIBS} mpfr" if [ -d "${FLINT_DIR}/lib" ]; then FLINT_LIB_DIR="${FLINT_DIR}/lib" FLINT_INC_DIR="${FLINT_DIR}/include" elif [ -d "${FLINT_DIR}/lib64" ]; then FLINT_LIB_DIR="${FLINT_DIR}/lib64" FLINT_INC_DIR="${FLINT_DIR}/include" elif [ -d "${FLINT_DIR}/.libs" ]; then FLINT_LIB_DIR="${FLINT_DIR}/.libs" FLINT_INC_DIR="${FLINT_DIR}" elif [ -d "${FLINT_DIR}" ]; then FLINT_LIB_DIR="${FLINT_DIR}" FLINT_INC_DIR="${FLINT_DIR}" else echo "Invalid FLINT directory" exit 1 fi if [ -d "${FLINT_INC_DIR}/flint" ]; then FLINT_INC_DIR="${FLINT_INC_DIR}" elif [ -f "${FLINT_INC_DIR}/flint.h" ]; then mkdir -p build/include ln -sf ${FLINT_INC_DIR} build/include/flint FLINT_INC_DIR="${PWD}/build/include" fi echo "FLINT_LIB_DIR set to ${FLINT_LIB_DIR}" echo "FLINT_INC_DIR set to ${FLINT_INC_DIR}" LIB_DIRS="${LIB_DIRS} ${FLINT_LIB_DIR}" INC_DIRS="${INC_DIRS} ${FLINT_INC_DIR}" LIBS="${LIBS} flint" if [ -d "${ARB_DIR}/lib" ]; then ARB_LIB_DIR="${ARB_DIR}/lib" ARB_INC_DIR="${ARB_DIR}/include" elif [ -d "${ARB_DIR}/lib64" ]; then ARB_LIB_DIR="${ARB_DIR}/lib64" ARB_INC_DIR="${ARB_DIR}/include" elif [ -d "${ARB_DIR}/.libs" ]; then ARB_LIB_DIR="${ARB_DIR}/.libs" ARB_INC_DIR="${ARB_DIR}" elif [ -d "${ARB_DIR}" ]; then ARB_LIB_DIR="${ARB_DIR}" ARB_INC_DIR="${ARB_DIR}" else echo "Invalid ARB directory" exit 1 fi echo "ARB_LIB_DIR set to ${ARB_LIB_DIR}" echo "ARB_INC_DIR set to ${ARB_INC_DIR}" LIB_DIRS="${LIB_DIRS} ${ARB_LIB_DIR}" INC_DIRS="${INC_DIRS} ${ARB_INC_DIR}" LIBS="${LIBS} arb" if [ -d "${ANTIC_DIR}/lib" ]; then ANTIC_LIB_DIR="${ANTIC_DIR}/lib" ANTIC_INC_DIR="${ANTIC_DIR}/include" elif [ -d "${ANTIC_DIR}/lib64" ]; then ANTIC_LIB_DIR="${ANTIC_DIR}/lib64" ANTIC_INC_DIR="${ANTIC_DIR}/include" elif [ -d "${ANTIC_DIR}/.libs" ]; then ANTIC_LIB_DIR="${ANTIC_DIR}/.libs" ANTIC_INC_DIR="${ANTIC_DIR}" elif [ -d "${ANTIC_DIR}" ]; then ANTIC_LIB_DIR="${ANTIC_DIR}" ANTIC_INC_DIR="${ANTIC_DIR}" else echo "Invalid ANTIC directory" exit 1 fi if [ -d "${ANTIC_INC_DIR}/antic" ]; then ANTIC_INC_DIR="${ANTIC_INC_DIR}" elif [ -f "${ANTIC_INC_DIR}/nf.h" ]; then mkdir -p build/include ln -sf ${ANTIC_INC_DIR} build/include/antic ANTIC_INC_DIR="${PWD}/build/include" fi echo "ANTIC_LIB_DIR set to ${ANTIC_LIB_DIR}" echo "ANTIC_INC_DIR set to ${ANTIC_INC_DIR}" LIB_DIRS="${LIB_DIRS} ${ANTIC_LIB_DIR}" INC_DIRS="${INC_DIRS} ${ANTIC_INC_DIR}" LIBS="${LIBS} antic" # defaults for CC, CXX and AR if [ -z "$CC" ]; then CC=gcc fi if [ -z "$CXX" ]; then CXX=g++ fi if [ -z "$AR" ]; then AR=ar fi # Architecture handler KERNEL=`uname` if [ -z "$BUILD" ]; then ARCH=`uname -m` if [ "$(uname | cut -d_ -f1)" = "MINGW32" ]; then if [ "$ABI" = "64" ]; then OS="MINGW64" else OS="MINGW32" fi elif [ "$(uname | cut -d_ -f1)" = "CYGWIN" ]; then if [ "$ARCH" = "x86_64" ]; then if [ "$ABI" = "32" ]; then OS="CYGWIN32" else OS="CYGWIN64" ABI="64" fi else OS="CYGWIN32" fi else OS=`uname -s` fi else ARCH=`echo "$BUILD" | cut -d- -f1` OS=`echo "$BUILD" | cut -d- -f2` fi case "$ARCH" in x86_64 | amd64) MACHINE="x86_64";; x86 | i*86 | pc) MACHINE="x86";; ia64) MACHINE="ia64";; sparc | sun4*) MACHINE="sparc";; sparc64) MACHINE="sparc64";; ppc64 | powerpc64) MACHINE="ppc64";; ppc | powerpc | [P|p]ower*) MACHINE="ppc";; *) MACHINE="unknown";; esac #ABI flag if [ "$ABI" = "32" ]; then ABI_FLAG="-m32" case "$MACHINE" in x86_64) MACHINE="x86";; sparc64) MACHINE="sparc";; ppc64) MACHINE="ppc";; *) ;; esac elif [ "$ABI" = "64" ]; then ABI_FLAG="-m64" if [ "$MACHINE" = "sparc" ]; then MACHINE="sparc64" fi if [ "$MACHINE" = "x86" ]; then MACHINE="x86_64" fi fi if [ "$MACHINE" = "sparc" ] || [ "$MACHINE" = "sparc64" ]; then if [ "$CC" = "gcc" ]; then CC="gcc -mno-relax" fi fi echo "Configuring...${MACHINE}-${OS}" #name for CALCIUM shared library CALCIUM_SOLIB=0 if [ -z "$CALCIUM_LIB" ]; then case "$OS" in Darwin) CALCIUM_LIBNAME="libcalcium.dylib" CALCIUM_LIB="libcalcium-$CALCIUM_MAJOR.$CALCIUM_MINOR.$CALCIUM_PATCH.dylib" EXTRA_SHARED_FLAGS="-install_name $PREFIX/lib/$CALCIUM_LIB -compatibility_version $CALCIUM_MAJOR.$CALCIUM_MINOR -current_version $CALCIUM_MAJOR.$CALCIUM_MINOR.$CALCIUM_PATCH";; CYGWIN* | MINGW*) CALCIUM_LIBNAME="libcalcium.dll" CALCIUM_LIB="libcalcium-$CALCIUM_MAJOR.dll" EXTRA_SHARED_FLAGS="-static-libgcc -shared -Wl,--export-all-symbols -Wl,-soname,libcalcium-$CALCIUM_MAJOR.dll.$CALCIUM_MINOR.$CALCIUM_PATCH";; *) CALCIUM_LIBNAME="libcalcium.so" CALCIUM_LIB="libcalcium.so.$CALCIUM_MAJOR.$CALCIUM_MINOR.$CALCIUM_PATCH" EXTRA_SHARED_FLAGS="-Wl,-soname,libcalcium.so.$CALCIUM_MAJOR" CALCIUM_SOLIB=1;; esac fi # sometimes LDCONFIG is not to be found in the path. Look at some common places. case "$OS" in MINGW*|CYGWIN*|Darwin) LDCONFIG="true";; *) if [ -z "$LDCONFIG" ]; then LDCONFIG="true" if [ "$CALCIUM_SOLIB" = "1" ]; then if command -v ldconfig > /dev/null; then LDCONFIG="ldconfig" elif [ -x /sbin/ldconfig ]; then LDCONFIG="/sbin/ldconfig" fi fi fi;; esac #extension for executables if [ -z "$EXEEXT" ]; then case "$OS" in CYGWIN* | MINGW*) EXEEXT=".exe";; *) EXEEXT="";; esac fi #don't build both shared and static lib on MinGW and Cygwin case "$OS" in CYGWIN* | MINGW*) if [ "$STATIC" = "1" ] && [ "$SHARED" = "1" ]; then echo "Building both static and shared versions of MPIR/GMP on $OS is currently" echo "unsupported, and so is it for MPFR, FLINT and ARB." echo "You should pass --disable-shared or --disable-static to configure" echo "depending on the versions of MPIR/GMP, MPFR and FLINT you built." exit 1 fi ;; *) ;; esac #test for popcnt flag and set needed CFLAGS #defaults for CFLAGS if [ -z "$CFLAGS" ]; then if [ "$OS" = "MINGW64" ]; then CFLAGS="-O2 -funroll-loops -g $POPCNT_FLAG $ABI_FLAG" elif [ "$OS" = "CYGWIN64" ]; then CFLAGS="-O2 -funroll-loops -g -D _WIN64 $POPCNT_FLAG $ABI_FLAG" else CFLAGS="-ansi -pedantic -Wall -O2 -funroll-loops -g $POPCNT_FLAG $ABI_FLAG" fi fi #this is needed on PPC G5 and does not hurt on other OS Xes if [ "$KERNEL" = Darwin ]; then CFLAGS="-fno-common $CFLAGS" fi #PIC flag if [ -z "$PIC_FLAG" ]; then case "$OS" in CYGWIN* | MINGW*) ;; *) PIC_FLAG="-fPIC";; esac fi #test support for thread-local storage CONFIG_TLS="#define HAVE_TLS 0" if [ "$TLS" = "1" ]; then mkdir -p build rm -f build/test-tls > /dev/null 2>&1 MSG="Testing __thread..." printf "%s" "$MSG" echo "__thread int x = 42; int main(int argc, char ** argv) { return x != 42; }" > build/test-tls.c $CC build/test-tls.c -o ./build/test-tls > /dev/null 2>&1 if [ $? -eq 0 ]; then build/test-tls > /dev/null 2>&1 if [ $? -eq 0 ]; then printf "%s\n" "yes" CONFIG_TLS="#define HAVE_TLS 1" else printf "%s\n" "no" fi rm -f build/test-tls{,.c} else rm -f build/test-tls.c printf "%s\n" "no" #build-tls can segfault on systems where tls is not available fi 2> /dev/null fi #pthread configuration CONFIG_PTHREAD="#define HAVE_PTHREAD ${PTHREAD}" #pocess external modules EXTRA_INC_DIRS="${EXTRA_INC_DIRS} ${EXTENSIONS}" if [ -d "${EXTENSIONS}/examples" ]; then cp ${EXTENSIONS}/examples/*.c ./examples/ fi #include paths INCS="-I\$(CURDIR)" for INC_DIR in ${INC_DIRS} ${EXTRA_INC_DIRS}; do INCS="${INCS} -I${INC_DIR}" done #library paths LLIBS="-L\$(CURDIR)" for LIB_DIR in ${LIB_DIRS} ${EXTRA_LIB_DIRS}; do LLIBS="${LLIBS} -L${LIB_DIR}" done #linker params if [ "$PTHREAD" = "1" ]; then lLIBS2="-lpthread ${lLIBS2}" fi for LIB in ${EXTRA_LIBS} ${LIBS}; do lLIBS2="-l${LIB} ${lLIBS2}" done lLIBS="-lcalcium $lLIBS2" LIBS2="$LLIBS $lLIBS2" LIBS="$LLIBS $lLIBS" #paths for dynamic linker case "$OS" in CYGWIN* | MINGW*) DLPATH="PATH";; Darwin) DLPATH="DYLD_LIBRARY_PATH";; sparc) DLPATH="LD_LIBRARY_PATH32";; sparc64) DLPATH="LD_LIBRARY_PATH64";; *) DLPATH="LD_LIBRARY_PATH";; esac DLPATH_ADD="\$(CURDIR)" for LIB_DIR in ${LIB_DIRS} ${EXTRA_LIB_DIRS}; do DLPATH_ADD="${DLPATH_ADD}:${LIB_DIR}" done #write out Makefile echo "# This file is autogenerated by ./configure -- do not edit!" > Makefile echo "" >> Makefile echo "SHELL=/bin/sh" >> Makefile echo "" >> Makefile echo "CALCIUM_STATIC=$STATIC" >> Makefile echo "CALCIUM_SHARED=$SHARED" >> Makefile echo "CALCIUM_LIB=$CALCIUM_LIB" >> Makefile echo "CALCIUM_LIBNAME=$CALCIUM_LIBNAME" >> Makefile echo "CALCIUM_MAJOR=$CALCIUM_MAJOR" >> Makefile echo "CALCIUM_SOLIB=$CALCIUM_SOLIB" >> Makefile echo "EXEEXT=$EXEEXT" >> Makefile echo "PREFIX=$PREFIX" >> Makefile echo "" >> Makefile echo "INCS=$INCS" >> Makefile echo "LIBS=$LIBS" >> Makefile echo "LIBS2=$LIBS2" >> Makefile echo "" >> Makefile echo "CC=$CC" >> Makefile echo "CXX=$CXX" >> Makefile echo "AR=$AR" >> Makefile echo "LDCONFIG=$LDCONFIG" >> Makefile echo "" >> Makefile echo "CFLAGS=$CFLAGS" >> Makefile echo "ABI_FLAG=$ABI_FLAG" >> Makefile echo "PIC_FLAG=$PIC_FLAG" >> Makefile echo "EXTRA_SHARED_FLAGS=$EXTRA_SHARED_FLAGS" >> Makefile echo "" >> Makefile echo "DLPATH=$DLPATH" >> Makefile echo "DLPATH_ADD=$DLPATH_ADD" >> Makefile echo "EXTENSIONS=$EXTENSIONS" >> Makefile echo "EXTRA_BUILD_DIRS=$EXTRA_BUILD" >> Makefile echo "" >> Makefile cat Makefile.in >> Makefile echo "Calcium was successfully configured." calcium-0.4.1/doc/000077500000000000000000000000001407704557200137115ustar00rootroot00000000000000calcium-0.4.1/doc/introduction.ipynb000066400000000000000000002070221407704557200175000ustar00rootroot00000000000000{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction to exact real and complex arithmetic with Calcium\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Author: Fredrik Johansson*\n", "\n", "This notebook gives an introduction to Calcium (https://fredrikj.net/calcium/), using the builtin ctypes-based Python wrapper.\n", "\n", "The source notebook file: https://github.com/fredrik-johansson/calcium/blob/master/doc/introduction.ipynb\n", "\n", "To run this Notebook locally, you need to build Calcium and add `calcium/pycalcium` to your Python path.\n", "\n", "*Caution*: the ctypes wrapper is incomplete, slow, and has some problems (e.g. memory leaks). It is mainly intended for testing the library. A more robust Cython interface should eventually be developed for \"production use\", along with a Julia interface. Calcium itself is also still experimental." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Imports\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# For convenience\n", "from IPython.display import display\n", "\n", "# Import the Calcium ctypes wrapper\n", "# Don't \"import *\" at home -- this is for demonstration use only\n", "from pyca import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Quick example: Euler's identity $e^{\\pi i} + 1 = 0$" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "exp(pi * i) + 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic types" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The core types implemented in Calcium are the following:\n", "\n", "* Symbolic expressions - `pyca.fexpr` (`fexpr_t` in C)\n", "* Algebraic numbers - `pyca.qqbar` (`qqbar_t` in C)\n", "* Calcium numbers / field elements - `pyca.ca` (`ca_t` in C)\n", "\n", "The types have different roles, and it is important to understand their differences.\n", "\n", "**Symbolic expressions** are the most flexible representation: they preserve the exact form of the input without performing any computation or simplification. For example, $\\sqrt{2} / 2$, $1 / \\sqrt{2}$ and $2^{1/2} / 2$ are all different as expressions (although they represent the same number). Symbolic expressions are not very useful on their own for computations, but they are convenient as input and output for other, more \"computational\" types.\n", "\n", "**Algebraic numbers** represent elements of the field $\\overline{\\mathbb{Q}}$ in *canonical form*, consisting of the number's minimal polynomial together with an isolating complex interval for a unique root. Thus one number can only have one representation: $\\sqrt{2} / 2$ and $1 / \\sqrt{2}$ will evaluate to exactly the same `qqbar` algebraic number. This is useful because the results are predictable and in a sense maximally simplified (contrary to the other types, it is impossible to construct a complicated `qqbar` instance that represents 0 without trivially being 0). The downsides are that field operations are much more expensive than in the `ca` representation, and in passing from a symbolic expression to a `qqbar`, structural information (such as a simple closed form) may be lost.\n", "\n", "**Calcium numbers** represent numbers as elements of fields $\\mathbb{Q}(a_1,\\ldots,a_n)$. Calcium constructs extension numbers $a_k$ and fields $\\mathbb{Q}(a_1,\\ldots,a_n)$ automatically and lazily, so from the point of view of the user Calcium numbers behave just like numbers. The extension numbers $a_k$ can be \"absolute\" algebraic numbers (`qqbar` instances), but they can also be transcendental numbers like $\\pi$ or $\\exp(\\sqrt{2} i)$. This representation is highly efficient for arithmetic, but in general does not guarantee a canonical form. Relations between extension elements (e.g. $\\log(4) / \\log(2) = 2$) are simplified automatically using ideal reduction, but Calcium will not be able to prove all relations, so it is possible to have a `ca` instance that represents 0 without trivially being 0 (such instances are nevertheless handled in a mathematically rigorous way as discussed below). The `ca` type can also represent special values and metavalues (signed and unsigned infinities, undefined, unknown)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Symbolic expressions\n", "\n", "In the `pyca` namespace, lowercase names (example: `sqrt`) denote `ca` functions while while uppercase names (example: `Sqrt`) denote `fexpr` symbolic expressions. It is easy to construct symbolic expressions:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{\\sqrt{2}}{2} + \\frac{1}{\\sqrt{2}} + \\frac{{2}^{1 / 2}}{2}$$" ], "text/plain": [ "Add(Div(Sqrt(2), 2), Div(1, Sqrt(2)), Div(Pow(2, Div(1, 2)), 2))" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a symbolic sum of three terms\n", "expr = Add(Sqrt(2) / 2, 1 / Sqrt(2), 2 ** Div(1, 2) / 2)\n", "# Display the formula\n", "expr" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "pyca.fexpr" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(expr)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Evaluating expressions and displaying objects" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Constant expressions can be passed as input to other types, resulting in evaluation:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{3 a_{1}}{2}\\; \\text{ where } a_{1} = \\sqrt{2}$$" ], "text/plain": [ "2.12132 {(3*a)/2 where a = 1.41421 [a^2-2=0]}" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ca(expr) # evaluate expr using ca arithmetic, producing a ca" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "pyca.ca" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(_)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\left(\\text{Root }\\, x \\approx {2.12132} \\;\\text{ of } \\;{2 x^{2}-9}\\right)$$" ], "text/plain": [ "2.12132 (deg 2)" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qqbar(expr) # evaluate expr using qqbar arithmetic, producing a qqbar" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "pyca.qqbar" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Symbolic expressions are also generated automatically behind the scenes in order to display objects in LaTeX in the notebook (this is done in the examples above). You can of course also print objects in text form:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Add(Div(Sqrt(2), 2), Div(1, Sqrt(2)), Div(Pow(2, Div(1, 2)), 2))\n", "2.12132 {(3*a)/2 where a = 1.41421 [a^2-2=0]}\n", "2.12132 (deg 2)\n" ] } ], "source": [ "print(expr)\n", "print(ca(expr))\n", "print(qqbar(expr))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By default, `qqbar` objects display as polynomial roots. To produce a closed-form expression (if possible), the `qqbar.fexpr()` method can be called:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{3 \\sqrt{2}}{2}$$" ], "text/plain": [ "Div(Mul(3, Sqrt(2)), 2)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qqbar(expr).fexpr()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Manipulating symbolic expressions\n", "\n", "The `fexpr` type provides methods for rudimentary manipulation (accessing subexpressions and so on)." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Add\n", "3\n", "(Div(Sqrt(2), 2), Div(1, Sqrt(2)), Div(Pow(2, Div(1, 2)), 2))\n", "False\n", "True\n", "16\n", "24\n", "Add(Div(Sqrt(Pi), Pi), Div(1, Sqrt(Pi)), Div(Pow(Pi, Div(1, Pi)), Pi))\n" ] } ], "source": [ "expr = Add(Sqrt(2) / 2, 1 / Sqrt(2), 2 ** Div(1, 2) / 2)\n", "print(expr.head())\n", "print(expr.nargs())\n", "print(expr.args())\n", "print(expr.is_atom())\n", "print(expr.args()[0].args()[1].is_atom())\n", "print(expr.num_leaves())\n", "print(expr.nwords())\n", "print(expr.replace(2, Pi))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `.nstr()` method computes a numerical approximation using Arb, returning a decimal string:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.707106781186547524400844362105\n", "-1.131204384 + 2.471726672*I\n", "-1.00000000000000000000000000000 + 0e-37*I\n", "0e-731\n" ] } ], "source": [ "print((Sqrt(2) / 2).nstr(30))\n", "print((Exp(1 + 2j).nstr(10)))\n", "\n", "# No symbolic simplification is done - Arb can generally not detect\n", "# exact zeros, and zeros will be output in the form 0e-n\n", "print((Exp(Pi*NumberI)).nstr(30))\n", "print((Sqrt(2)/2 - 1/Sqrt(2)).nstr())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `.expanded_normal_form()` method puts the given formula in a canonical form as a formal rational expression." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{{x}^{4} + 4 {x}^{3} y + 6 {x}^{2} {y}^{2} + 4 x {y}^{3} + {y}^{4}}{x-1}$$" ], "text/plain": [ "Div(Add(Pow(x, 4), Mul(4, Pow(x, 3), y), Mul(6, Pow(x, 2), Pow(y, 2)), Mul(4, x, Pow(y, 3)), Pow(y, 4)), Add(x, -1))" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = fexpr(\"x\"); y = fexpr(\"y\")\n", "A = (x+y)**5 * (x-y) * (x + 1)\n", "B = (x**2 - y**2) * (x**2 - 1)\n", "(A / B).expanded_normal_form()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Please note that `.expanded_normal_form()` only simplifies rational arithmetic operations, treating anything non-arithmetical as an atomic node. For example, square roots are treated as atomic. It also does not simplify nodes recursively." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$1$$" ], "text/plain": [ "1" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$${\\left(\\sqrt{x}\\right)}^{2}$$" ], "text/plain": [ "Pow(Sqrt(x), 2)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$\\frac{\\sqrt{2 x}}{\\sqrt{x \\cdot 2}}$$" ], "text/plain": [ "Div(Sqrt(Mul(2, x)), Sqrt(Mul(x, 2)))" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display((Sqrt(x) / Sqrt(x)).expanded_normal_form())\n", "display((Sqrt(x) * Sqrt(x)).expanded_normal_form())\n", "display((Sqrt(2*x) / Sqrt(x*2)).expanded_normal_form())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will not do anything more sophisticated with symbolic expressions in this notebook; we will instead move on to describing exact numerical calculations using the `ca` and `qqbar` types." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Calcium numbers\n", "\n", "Calcium numbers encompass rational numbers, of course:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{1}{3}$$" ], "text/plain": [ "0.333333 {1/3}" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ca(1) / 3" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$2$$" ], "text/plain": [ "2" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(ca(1) / 3) * 6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Irrational numbers result in extensions of $\\mathbb{Q}$:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$a_{1}\\; \\text{ where } a_{1} = \\sqrt{2}$$" ], "text/plain": [ "1.41421 {a where a = 1.41421 [a^2-2=0]}" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Alternative syntax: ca(2).sqrt()\n", "sqrt(2)" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$2$$" ], "text/plain": [ "2" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sqrt(2) ** 2" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$2 a_{1}\\; \\text{ where } a_{1} = \\pi$$" ], "text/plain": [ "6.28319 {2*a where a = 3.14159 [Pi]}" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2 * pi" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Field arithmetic produces numbers represented as formal fraction field elements:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$a_{1} a_{2} a_{3}\\; \\text{ where } a_{1} = \\pi,\\;a_{2} = \\sqrt{2},\\;a_{3} = i$$" ], "text/plain": [ "4.44288*I {a*b*c where a = 3.14159 [Pi], b = 1.41421 [b^2-2=0], c = I [c^2+1=0]}" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pi * i * sqrt(2)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$-2 a^{2}_{1}\\; \\text{ where } a_{1} = \\pi,\\;a_{2} = \\sqrt{2},\\;a_{3} = i$$" ], "text/plain": [ "-19.7392 {-2*a^2 where a = 3.14159 [Pi], b = 1.41421 [b^2-2=0], c = I [c^2+1=0]}" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(pi * i * sqrt(2)) ** 2 # note the simplifications" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{a^{3}_{1} + 3 a^{2}_{1} a_{2} + 3 a^{2}_{1} a_{3} + 6 a_{1} a_{2} a_{3} + 3 a_{1}- a_{2} + 5 a_{3}}{a^{3}_{1} + 3 a^{2}_{1} a_{2} + 6 a_{1} + 2 a_{2}}\\; \\text{ where } a_{1} = \\pi,\\;a_{2} = \\sqrt{2},\\;a_{3} = i$$" ], "text/plain": [ "0.855459 + 0.647925*I {(a^3+3*a^2*b+3*a^2*c+6*a*b*c+3*a-b+5*c)/(a^3+3*a^2*b+6*a+2*b) where a = 3.14159 [Pi], b = 1.41421 [b^2-2=0], c = I [c^2+1=0]}" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "((pi + i + sqrt(2)) / (pi + sqrt(2)))**3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Some more number field arithmetic" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us construct the golden ratio:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{a_{1} + 1}{2}\\; \\text{ where } a_{1} = \\sqrt{5}$$" ], "text/plain": [ "1.61803 {(a+1)/2 where a = 2.23607 [a^2-5=0]}" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "phi = (sqrt(5) + 1) / 2\n", "phi" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We compute the 200th Fibonacci number using Binet's formula:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$280571172992510140037611932413038677189525$$" ], "text/plain": [ "2.80571e+41 {280571172992510140037611932413038677189525}" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(phi**200 - (1-phi)**200) / sqrt(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Depending on the operations, `ca` arithmetic may result in different field representations of the same number:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$a_{1} a_{2}\\; \\text{ where } a_{1} = \\sqrt{3},\\;a_{2} = \\sqrt{2}$$" ], "text/plain": [ "2.44949 {a*b where a = 1.73205 [a^2-3=0], b = 1.41421 [b^2-2=0]}" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$a_{1}\\; \\text{ where } a_{1} = \\sqrt{6}$$" ], "text/plain": [ "2.44949 {a where a = 2.44949 [a^2-6=0]}" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(sqrt(2)*sqrt(3))\n", "display(sqrt(6))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The difference simplifies to zero:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "True" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(sqrt(2)*sqrt(3) - sqrt(6))\n", "display(sqrt(2)*sqrt(3) == sqrt(6))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calcium will attempt to eliminate more complex extension numbers when it encounters extension numbers that are algebraically dependent. Here, it eliminates $\\sqrt{6}$ from the expression, writing the result in terms of $\\sqrt{2}$ and $\\sqrt{3}$" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$2 a_{2} a_{3}\\; \\text{ where } a_{1} = \\sqrt{6},\\;a_{2} = \\sqrt{3},\\;a_{3} = \\sqrt{2}$$" ], "text/plain": [ "4.89898 {2*b*c where a = 2.44949 [a^2-6=0], b = 1.73205 [b^2-3=0], c = 1.41421 [c^2-2=0]}" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sqrt(2)*sqrt(3) + sqrt(6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(Implementation detail: the output shows that $\\sqrt{6}$ is still kept as part of the field structure, to aid future simplifications, although it is unused in this particular field element.)\n", "\n", "In many cases, it would be desirable to write the above result as an element of the simple algebraic number field $\\mathbb{Q}(\\sqrt{6})$ or $\\mathbb{Q}(\\sqrt{2} + \\sqrt{3})$ instead. Calcium will always stay within a univariate field when performing field operations starting from a single extension number, but it will not automatically reduce multivariate number fields to univariate fields. In the future, Calcium will offer more customizability so that the user can choose between different behaviors concerning simplification of extension numbers and fields." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Predicates; contexts objects" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Predicates in Calcium have mathematically semantics: they return True or False only if Calcium can prove the result. When the truth value is unknown, Calcium says so explicitly; in `pyca`, this is done by raising an exception (`NotImplementedError`). Consider, as an example, testing whether $\\exp(\\varepsilon) = 1$ where $\\varepsilon$ is a small number. With $\\varepsilon = 10^{-1000}$, Calcium finds that the numbers are not equal:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "eps = ca(10) ** (-1000)\n", "exp(eps) == 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With $\\varepsilon = 10^{-10000}$, Calcium fails:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "unable to decide predicate: equal\n" ] } ], "source": [ "eps = ca(10) ** (-10000)\n", "try:\n", " exp(eps) == 1\n", "except Exception as e:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The comparison fails because the internal precision limit for numerical evaluation has been exceeded. The precision limit and many other settings are stored in a context object, which also serves as a cache of computed data (such as extension numbers and extension fields). The context object has type `ca_ctx`. There is a default context called `ctx_default`, with the following settings:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "ca_ctx(verbose=0, print_flags=3, mpoly_ord=0, prec_limit=4096, qqbar_deg_limit=120, low_prec=64, smooth_limit=32, lll_prec=128, pow_limit=20, use_gb=1, gb_length_limit=100, gb_poly_length_limit=1000, gb_poly_bits_limit=10000, vieta_limit=6)" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ctx_default" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we create a new context object with higher `prec_limit` than the default value of 4096 bits, the computation succeeds:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ctx = ca_ctx(prec_limit=65536)\n", "eps = ca(10, context=ctx) ** (-10000)\n", "exp(eps) == 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The intention is that the user will be able to create multiple \"Calcium fields\" for different purposes. Right now, context objects support only limited configurability." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Algebraic number identities" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calcium implements a complete decision procedure for testing equality (or inequality) of algebraic numbers. This functionality is accessible using either `qqbar` or `ca` operations.\n", "\n", "Rob Corless proposed checking the following identity from Bill Gosper. We will first construct the LHS and RHS as symbolic expressions. We could evaluate them directly with `qqbar` or `ca` operations, which would be more efficient, but this way we can print the input." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{\\sqrt{36 + 3 {\\left(-54 + 35 i \\sqrt{3}\\right)}^{1 / 3} \\cdot {3}^{1 / 3} + \\frac{117}{{\\left(-162 + 105 i \\sqrt{3}\\right)}^{1 / 3}}}}{3} + \\frac{\\sqrt{5} \\left(1296 i + 840 \\sqrt{3} - 35 \\cdot {3}^{5 / 6} {\\left(-54 + 35 i \\sqrt{3}\\right)}^{1 / 3} - 54 i {\\left(-162 + 105 i \\sqrt{3}\\right)}^{1 / 3} + 13 i {\\left(-162 + 105 i \\sqrt{3}\\right)}^{2 / 3}\\right)}{5 \\left(162 i + 105 \\sqrt{3}\\right)} = \\sqrt{5} + \\sqrt{7}$$" ], "text/plain": [ "Equal(Add(Div(Sqrt(Add(Add(36, Mul(Mul(3, Pow(Add(-54, Mul(Mul(35, NumberI), Sqrt(3))), Div(1, 3))), Pow(3, Div(1, 3)))), Div(117, Pow(Add(-162, Mul(Mul(105, NumberI), Sqrt(3))), Div(1, 3))))), 3), Div(Mul(Sqrt(5), Add(Sub(Sub(Add(Mul(1296, NumberI), Mul(840, Sqrt(3))), Mul(Mul(35, Pow(3, Div(5, 6))), Pow(Add(-54, Mul(Mul(35, NumberI), Sqrt(3))), Div(1, 3)))), Mul(Mul(54, NumberI), Pow(Add(-162, Mul(Mul(105, NumberI), Sqrt(3))), Div(1, 3)))), Mul(Mul(13, NumberI), Pow(Add(-162, Mul(Mul(105, NumberI), Sqrt(3))), Div(2, 3))))), Mul(5, Add(Mul(162, NumberI), Mul(105, Sqrt(3)))))), Add(Sqrt(5), Sqrt(7)))" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "I = NumberI\n", "\n", "lhs = Sqrt(36 + 3*(-54+35*I*Sqrt(3))**Div(1,3)*3**Div(1,3) + \\\n", " 117/(-162+105*I*Sqrt(3))**Div(1,3))/3 + \\\n", " Sqrt(5)*(1296*I+840*Sqrt(3)-35*3**Div(5,6)*(-54+35*I*Sqrt(3))**Div(1,3)-\\\n", " 54*I*(-162+105*I*Sqrt(3))**Div(1,3)+13*I*(-162+105*I*Sqrt(3))**Div(2,3))/(5*(162*I+105*Sqrt(3)))\n", "\n", "rhs = Sqrt(5) + Sqrt(7)\n", "\n", "display(Equal(lhs, rhs))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can check numerically that the expressions agree:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4.881819288564380 - 0e-20*I\n", "4.881819288564380\n" ] } ], "source": [ "print(lhs.nstr()); print(rhs.nstr())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Evaluating the expressions as `qqbar`s gives the same result, proving the identity: " ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\left(\\text{Root }\\, x \\approx {4.88182} \\;\\text{ of } \\;{ x^{4}-24 x^{2}+4}\\right)$$" ], "text/plain": [ "4.88182 (deg 4)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$\\left(\\text{Root }\\, x \\approx {4.88182} \\;\\text{ of } \\;{ x^{4}-24 x^{2}+4}\\right)$$" ], "text/plain": [ "4.88182 (deg 4)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(qqbar(lhs)); display(qqbar(rhs))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Explicitly:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "qqbar(lhs) == qqbar(rhs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also perform the verification using `ca` arithmetic. The equality is not immediately apparent since the two expressions evaluate to elements of different extension fields of $\\mathbb{Q}$:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{5 a_{1}- a^{2}_{4} a^{2}_{6} a_{7} + 24 a_{4} a_{6} a_{7}-39 a_{7}}{15 a_{4} a_{6}}\\; \\text{ where } a_{1} = \\sqrt{9 a^{3}_{4} + 36 a^{2}_{4} a^{2}_{6} + 117 a_{4} a_{6}},\\;a_{2} = {\\left(105 a_{8} a_{9}-162\\right)}^{2 / 3},\\;a_{3} = {\\left(105 a_{8} a_{9}-162\\right)}^{1 / 3},\\;a_{4} = {\\left(35 a_{8} a_{9}-54\\right)}^{1 / 3},\\;a_{5} = {3}^{5 / 6},\\;a_{6} = {3}^{1 / 3},\\;a_{7} = \\sqrt{5},\\;a_{8} = \\sqrt{3},\\;a_{9} = i$$" ], "text/plain": [ "4.88182 + 0e-33*I {(5*a-d^2*f^2*g+24*d*f*g-39*g)/(15*d*f) where a = 35.7176 + 34.3693*I [Sqrt(94.5000 + 2455.18*I {9*d^3+36*d^2*f^2+117*d*f})], b = 1.50000 + 38.9711*I [Pow(-162.000 + 181.865*I {105*h*i-162}, 0.666667 {2/3})], c = 4.50000 + 4.33013*I [Pow(-162.000 + 181.865*I {105*h*i-162}, 0.333333 {1/3})], d = 3.12013 + 3.00234*I [Pow(-54.0000 + 60.6218*I {35*h*i-54}, 0.333333 {1/3})], e = 2.49805 [Pow(3, 0.833333 {5/6})], f = 1.44225 [Pow(3, 0.333333 {1/3})], g = 2.23607 [g^2-5=0], h = 1.73205 [h^2-3=0], i = I [i^2+1=0]}" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(ca(lhs))" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$a_{1} + a_{2}\\; \\text{ where } a_{1} = \\sqrt{7},\\;a_{2} = \\sqrt{5}$$" ], "text/plain": [ "4.88182 {a+b where a = 2.64575 [a^2-7=0], b = 2.23607 [b^2-5=0]}" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(ca(rhs))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fortunately, the equality operator manages to prove that the values are really equal:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ca(lhs) == ca(rhs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Indeed, in this case `ca` arithmetic simplifies the difference of the expressions to 0 automatically:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ca(lhs) - ca(rhs)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If this example did not look challenging enough, you may try proving equality of the two huge expressions (involving 7000 operations) given in https://ask.sagemath.org/question/52653/equality-of-algebraic-numbers-given-by-huge-symbolic-expressions/. You will need a bit of string preprocessing to convert the given Sage expressions to `fexpr` expressions or ordinary Python syntax for use with the `ca` or `qqbar` types.\n", "\n", "This test problem is implemented in the `huge_expr.c` program in the Calcium examples directory. It should take a few seconds to run." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Transcendental number identities" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calcium is capable of manipulating numbers involving some transcendental functions such as `exp` and `log`. Contrary to the case of algebraic numbers, it does not have a complete decision procedure for transcendental numbers, but it has some decent heuristics." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exp and log numbers\n", "\n", "Basic logarithmic and exponential simplifications work as expected:" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$10$$" ], "text/plain": [ "10" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "log(10**20) / log(100)" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$2$$" ], "text/plain": [ "2" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "exp(pi) * exp(-pi + log(2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Different formulas for the same number may result in different internal field representations, in which case Calcium may yet be able to recognize relations when the numbers are subtracted or divided or when evaluating a predicate:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$a_{1}\\; \\text{ where } a_{1} = \\log(a_{2}),\\;a_{2} = \\sqrt{2}$$" ], "text/plain": [ "0.346574 {a where a = 0.346574 [Log(1.41421 {b})], b = 1.41421 [b^2-2=0]}" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$\\frac{a_{1}}{2}\\; \\text{ where } a_{1} = \\log(2)$$" ], "text/plain": [ "0.346574 {(a)/2 where a = 0.693147 [Log(2)]}" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$1$$" ], "text/plain": [ "1" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$\\frac{a^{2}_{2}}{4}\\; \\text{ where } a_{1} = \\log(a_{3}),\\;a_{2} = \\log(2),\\;a_{3} = \\sqrt{2}$$" ], "text/plain": [ "0.120113 {(b^2)/4 where a = 0.346574 [Log(1.41421 {c})], b = 0.693147 [Log(2)], c = 1.41421 [c^2-2=0]}" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "True" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "display(log(sqrt(2)))\n", "display(log(2)/2)\n", "display(log(sqrt(2)) - log(2)/2)\n", "display(log(sqrt(2)) / (log(2)/2))\n", "display(log(sqrt(2)) * (log(2)/2))\n", "log(sqrt(2)) == log(2)/2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calcium is aware of branch cuts:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$10 a_{1} + 1\\; \\text{ where } a_{1} = i$$" ], "text/plain": [ "1.00000 + 10.0000*I {10*a+1 where a = I [a^2+1=0]}" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$-4 a_{1} a_{2} + 10 a_{2} + 1\\; \\text{ where } a_{1} = \\pi,\\;a_{2} = i$$" ], "text/plain": [ "1.00000 - 2.56637*I {-4*a*b+10*b+1 where a = 3.14159 [Pi], b = I [b^2+1=0]}" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# exp(log(x)) == x\n", "display(exp(log(1 + 10*i)))\n", "# log(exp(x)) != x in general; here we get the correct branch!\n", "display(log(exp(1 + 10*i)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us check the formulas given on the Calcium documentation front page:" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{1}{2}$$" ], "text/plain": [ "0.500000 {1/2}" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "log(sqrt(2)+sqrt(3)) / log(5 + 2*sqrt(6))" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "i**i - exp(pi / ((sqrt(-2)**sqrt(2)) ** sqrt(2)))" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ca(10)**-30 < (640320**3 + 744)/exp(pi*sqrt(163)) - 1 < ca(10)**-29" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Trigonometric functions\n", "\n", "Calcium does not yet have trigonometric or inverse trigonometric funtions builtin at the C level, but we can \"fake\" these functions using complex exponentials and logarithms. The functions `pyca.sin`, `pyca.cos`, `pyca.tan` and `pyca.atan` do precisely this." ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{- a^{2}_{1} a_{2} + a_{2}}{2 a_{1}}\\; \\text{ where } a_{1} = e^{3 a_{2}},\\;a_{2} = i$$" ], "text/plain": [ "0.141120 - 0e-34*I {(-a^2*b+b)/(2*a) where a = -0.989992 + 0.141120*I [Exp(3.00000*I {3*b})], b = I [b^2+1=0]}" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sin(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calcium is capable of proving some trigonometric identities:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$1$$" ], "text/plain": [ "1" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sin(sqrt(2)/2)**2 + cos(1/sqrt(2))**2" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sin(3 + pi) + sin(3)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tan(atan(5)) == 5" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "This simplification does not work yet\n" ] } ], "source": [ "try:\n", " atan(tan(1)) == 1\n", "except NotImplementedError:\n", " print(\"This simplification does not work yet\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We test some simplifications involving the Gudermannian function $\\operatorname{gd}(x) = 2 \\operatorname{atan}(e^x) - \\pi/2$:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def gd(x):\n", " return 2*atan(exp(x))-pi/2\n", "\n", "display(sin(gd(1)) - tanh(1))\n", "display(tan(gd(1)) - sinh(1))\n", "display(sin(gd(sqrt(2))) - tanh(sqrt(2)))\n", "display(tan(gd(1)/2) - tanh(ca(1)/2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let us try to prove a famous identity; Machin's formula for $\\pi$:" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$4 \\operatorname{atan}\\!\\left(\\frac{1}{5}\\right) - \\operatorname{atan}\\!\\left(\\frac{1}{239}\\right) = \\frac{\\pi}{4}$$" ], "text/plain": [ "Equal(Sub(Mul(4, Atan(Div(1, 5))), Atan(Div(1, 239))), Div(Pi, 4))" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lhs = 4*Atan(Div(1,5)) - Atan(Div(1,239))\n", "rhs = Pi / 4\n", "Equal(lhs, rhs)" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.7853981633974483\n", "0.7853981633974483\n" ] } ], "source": [ "print(lhs.nstr())\n", "print(rhs.nstr())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Evaluating the left-hand side using `ca` arithmetic gives us nothing as simple as $\\pi / 4$:" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{a_{1} a_{3}-4 a_{2} a_{3}}{2}\\; \\text{ where } a_{1} = \\log\\!\\left(\\frac{239 a_{3} + 28560}{28561}\\right),\\;a_{2} = \\log\\!\\left(\\frac{5 a_{3} + 12}{13}\\right),\\;a_{3} = i$$" ], "text/plain": [ "0.785398 + 0e-34*I {(a*c-4*b*c)/2 where a = 0e-35 + 0.00836815*I [Log(0.999965 + 0.00836805*I {(239*c+28560)/28561})], b = 0e-34 + 0.394791*I [Log(0.923077 + 0.384615*I {(5*c+12)/13})], c = I [c^2+1=0]}" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "4*atan(ca(1)/5) - atan(ca(1)/239)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nevertheless, Calcium finds the identity when $\\pi$ is given as part of the input:" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "4*atan(ca(1)/5) - atan(ca(1)/239) - pi/4" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "4*atan(ca(1)/5) - atan(ca(1)/239) == pi/4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here is a more complicated formula:" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\frac{-12 a_{1} a_{5} + 5 a_{2} a_{5}-32 a_{3} a_{5}-12 a_{4} a_{5}}{2}\\; \\text{ where } a_{1} = \\log\\!\\left(\\frac{110443 a_{5} + 6098828124}{6098828125}\\right),\\;a_{2} = \\log\\!\\left(\\frac{239 a_{5} + 28560}{28561}\\right),\\;a_{3} = \\log\\!\\left(\\frac{57 a_{5} + 1624}{1625}\\right),\\;a_{4} = \\log\\!\\left(\\frac{49 a_{5} + 1200}{1201}\\right),\\;a_{5} = i$$" ], "text/plain": [ "0.785398 + 0e-33*I {(-12*a*e+5*b*e-32*c*e-12*d*e)/2 where a = 0e-35 + 1.81089e-5*I [Log(1.00000 + 1.81089e-5*I {(110443*e+6098828124)/6098828125})], b = 0e-35 + 0.00836815*I [Log(0.999965 + 0.00836805*I {(239*e+28560)/28561})], c = 0e-34 + 0.0350841*I [Log(0.999385 + 0.0350769*I {(57*e+1624)/1625})], d = 0e-35 + 0.0408107*I [Log(0.999167 + 0.0407993*I {(49*e+1200)/1201})], e = I [e^2+1=0]}" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "12*atan(ca(1)/49) + 32*atan(ca(1)/57) - 5*atan(ca(1)/239) + 12*atan(ca(1)/110443)" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "12*atan(ca(1)/49) + 32*atan(ca(1)/57) - 5*atan(ca(1)/239) + 12*atan(ca(1)/110443) - pi/4" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Hyperbolic formulas also work:" ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$-7 a_{1}-12 a_{2}-16 a_{3}\\; \\text{ where } a_{1} = \\log\\!\\left(\\frac{80}{81}\\right),\\;a_{2} = \\log\\!\\left(\\frac{24}{25}\\right),\\;a_{3} = \\log\\!\\left(\\frac{15}{16}\\right),\\;a_{4} = i$$" ], "text/plain": [ "1.60944 {-7*a-12*b-16*c where a = -0.0124225 [Log(0.987654 {80/81})], b = -0.0408220 [Log(0.960000 {24/25})], c = -0.0645385 [Log(0.937500 {15/16})], d = I [d^2+1=0]}" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "atanh = lambda x: -i*atan(i*x)\n", "32*atanh(ca(1)/31) + 24*atanh(ca(1)/49) + 14*atanh(ca(1)/161)" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "32*atanh(ca(1)/31) + 24*atanh(ca(1)/49) + 14*atanh(ca(1)/161) - log(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Matrices\n", "\n", "The `ca_mat` type provides matrices with `ca` entries. We look at some examples of basic manipulation:" ] }, { "cell_type": "code", "execution_count": 62, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\displaystyle{\\begin{pmatrix}1 & a_{1} a_{2} \\\\- a_{1} a_{2} & 2\\end{pmatrix}}\\; \\text{ where } a_{1} = \\pi,\\;a_{2} = i$$" ], "text/plain": [ "ca_mat of size 2 x 2\n", "[ 1, 3.14159*I {a*b where a = 3.14159 [Pi], b = I [b^2+1=0]}]\n", "[-3.14159*I {-a*b where a = 3.14159 [Pi], b = I [b^2+1=0]}, 2]" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = ca_mat([[1, i*pi], [-i*pi, 2]])\n", "A" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\displaystyle{\\begin{pmatrix}a^{2}_{1} + 1 & 3 a_{1} a_{2} \\\\-3 a_{1} a_{2} & a^{2}_{1} + 4\\end{pmatrix}}\\; \\text{ where } a_{1} = \\pi,\\;a_{2} = i$$" ], "text/plain": [ "ca_mat of size 2 x 2\n", "[ 10.8696 {a^2+1 where a = 3.14159 [Pi], b = I [b^2+1=0]}, 9.42478*I {3*a*b where a = 3.14159 [Pi], b = I [b^2+1=0]}]\n", "[-9.42478*I {-3*a*b where a = 3.14159 [Pi], b = I [b^2+1=0]}, 13.8696 {a^2+4 where a = 3.14159 [Pi], b = I [b^2+1=0]}]" ] }, "execution_count": 63, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A * A" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$- a^{2}_{1} + 2\\; \\text{ where } a_{1} = \\pi,\\;a_{2} = i$$" ], "text/plain": [ "-7.86960 {-a^2+2 where a = 3.14159 [Pi], b = I [b^2+1=0]}" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$3$$" ], "text/plain": [ "3" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "2" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "display(A.det())\n", "display(A.trace())\n", "display(A.rank())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Solving linear systems:" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\displaystyle{\\begin{pmatrix}\\frac{2 a_{1} a_{2}-2}{a^{2}_{1}-2} \\\\\\frac{- a_{1} a_{2}-2}{a^{2}_{1}-2}\\end{pmatrix}}\\; \\text{ where } a_{1} = \\pi,\\;a_{2} = i$$" ], "text/plain": [ "ca_mat of size 2 x 1\n", "[-0.254142 + 0.798412*I {(2*a*b-2)/(a^2-2) where a = 3.14159 [Pi], b = I [b^2+1=0]}]\n", "[ -0.254142 - 0.399206*I {(-a*b-2)/(a^2-2) where a = 3.14159 [Pi], b = I [b^2+1=0]}]" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$\\displaystyle{\\begin{pmatrix}1 \\\\2\\end{pmatrix}}$$" ], "text/plain": [ "ca_mat of size 2 x 1\n", "[1]\n", "[2]" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "B = ca_mat([[1], [2]])\n", "X = A.solve(B)\n", "display(X)\n", "display(A * X)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Computing row echelon forms and characteristic polynomials:" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\displaystyle{\\begin{pmatrix}1 & 0 & 0 & \\frac{a^{3}_{1}- a^{2}_{1}-2 a_{1}}{3 a^{2}_{1} + 3 a_{1}-2} \\\\0 & 1 & 0 & \\frac{4 a^{2}_{1} + 4 a_{1}-2}{3 a^{2}_{1} + 3 a_{1}-2} \\\\0 & 0 & 1 & \\frac{- a^{3}_{1} + a_{1}}{3 a^{2}_{1} + 3 a_{1}-2}\\end{pmatrix}}\\; \\text{ where } a_{1} = \\pi$$" ], "text/plain": [ "ca_mat of size 3 x 4\n", "[1, 0, 0, 0.401081 {(a^3-a^2-2*a)/(3*a^2+3*a-2) where a = 3.14159 [Pi]}]\n", "[0, 1, 0, 1.35134 {(4*a^2+4*a-2)/(3*a^2+3*a-2) where a = 3.14159 [Pi]}]\n", "[0, 0, 1, -0.752416 {(-a^3+a)/(3*a^2+3*a-2) where a = 3.14159 [Pi]}]" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ca_mat([[1,pi,2,pi],[1/pi,3,1/(pi+1),4],[1,1,1,1]]).rref()" ] }, { "cell_type": "code", "execution_count": 67, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\displaystyle{\\begin{pmatrix}a^{2}_{1} + 66 a_{1} + 625 & 8 a^{2}_{1} + 104 a_{1} \\\\8 a_{1} + 104 & a^{2}_{1} + 18 a_{1} + 1\\end{pmatrix}}\\; \\text{ where } a_{1} = \\pi$$" ], "text/plain": [ "ca_mat of size 2 x 2\n", "[842.215 {a^2+66*a+625 where a = 3.14159 [Pi]}, 405.682 {8*a^2+104*a where a = 3.14159 [Pi]}]\n", "[ 129.133 {8*a+104 where a = 3.14159 [Pi]}, 67.4183 {a^2+18*a+1 where a = 3.14159 [Pi]}]" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$ x^{2}+ \\left(-2 a^{2}_{1}-84 a_{1}-626\\right) x+ \\left(a^{4}_{1} + 20 a^{3}_{1} + 150 a^{2}_{1} + 500 a_{1} + 625\\right)\\; \\text{ where } a_{1} = \\pi$$" ], "text/plain": [ "ca_poly of length 3\n", "[4393.77 {a^4+20*a^3+150*a^2+500*a+625 where a = 3.14159 [Pi]}, -909.633 {-2*a^2-84*a-626 where a = 3.14159 [Pi]}, 1]" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/latex": [ "$$\\displaystyle{\\begin{pmatrix}0 & 0 \\\\0 & 0\\end{pmatrix}}$$" ], "text/plain": [ "ca_mat of size 2 x 2\n", "[0, 0]\n", "[0, 0]" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "A = ca_mat([[5, pi], [1, -1]])**4\n", "display(A)\n", "display(A.charpoly())\n", "display(A.charpoly()(A))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calcium correctly recognizes singular matrices, even matrices that are nontrivially singular." ] }, { "cell_type": "code", "execution_count": 68, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\displaystyle{\\begin{pmatrix}a_{1} & a^{2}_{1} \\\\a^{3}_{1} & a^{4}_{1}\\end{pmatrix}}\\; \\text{ where } a_{1} = \\pi$$" ], "text/plain": [ "ca_mat of size 2 x 2\n", "[ 3.14159 {a where a = 3.14159 [Pi]}, 9.86960 {a^2 where a = 3.14159 [Pi]}]\n", "[31.0063 {a^3 where a = 3.14159 [Pi]}, 97.4091 {a^4 where a = 3.14159 [Pi]}]" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = ca_mat([[pi, pi**2], [pi**3, pi**4]])\n", "A" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "matrix is singular!\n" ] } ], "source": [ "try:\n", " A.solve(ca_mat([[1], [2]]))\n", "except ZeroDivisionError:\n", " print(\"matrix is singular!\")" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\displaystyle{\\begin{pmatrix}1 & a_{1} \\\\0 & 0\\end{pmatrix}}\\; \\text{ where } a_{1} = \\pi$$" ], "text/plain": [ "ca_mat of size 2 x 2\n", "[1, 3.14159 {a where a = 3.14159 [Pi]}]\n", "[0, 0]" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.rref()" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.rank()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Exact matrix operations easily result in large expressions:" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\displaystyle{\\begin{pmatrix}1 & a_{7} & a_{6} & 2 & a_{5} & a_{4} \\\\a_{7} & a_{6} & 2 & a_{5} & a_{4} & a_{3} \\\\a_{6} & 2 & a_{5} & a_{4} & a_{3} & 2 a_{7} \\\\2 & a_{5} & a_{4} & a_{3} & 2 a_{7} & 3 \\\\a_{5} & a_{4} & a_{3} & 2 a_{7} & 3 & a_{2} \\\\a_{4} & a_{3} & 2 a_{7} & 3 & a_{2} & a_{1}\\end{pmatrix}}\\; \\text{ where } a_{1} = \\sqrt{11},\\;a_{2} = \\sqrt{10},\\;a_{3} = \\sqrt{7},\\;a_{4} = \\sqrt{6},\\;a_{5} = \\sqrt{5},\\;a_{6} = \\sqrt{3},\\;a_{7} = \\sqrt{2}$$" ], "text/plain": [ "ca_mat of size 6 x 6\n", "[ 1, 1.41421 {a where a = 1.41421 [a^2-2=0]}, 1.73205 {a where a = 1.73205 [a^2-3=0]}, 2, 2.23607 {a where a = 2.23607 [a^2-5=0]}, 2.44949 {a where a = 2.44949 [a^2-6=0]}]\n", "[1.41421 {a where a = 1.41421 [a^2-2=0]}, 1.73205 {a where a = 1.73205 [a^2-3=0]}, 2, 2.23607 {a where a = 2.23607 [a^2-5=0]}, 2.44949 {a where a = 2.44949 [a^2-6=0]}, 2.64575 {a where a = 2.64575 [a^2-7=0]}]\n", "[1.73205 {a where a = 1.73205 [a^2-3=0]}, 2, 2.23607 {a where a = 2.23607 [a^2-5=0]}, 2.44949 {a where a = 2.44949 [a^2-6=0]}, 2.64575 {a where a = 2.64575 [a^2-7=0]}, 2.82843 {2*a where a = 1.41421 [a^2-2=0]}]\n", "[ 2, 2.23607 {a where a = 2.23607 [a^2-5=0]}, 2.44949 {a where a = 2.44949 [a^2-6=0]}, 2.64575 {a where a = 2.64575 [a^2-7=0]}, 2.82843 {2*a where a = 1.41421 [a^2-2=0]}, 3]\n", "[2.23607 {a where a = 2.23607 [a^2-5=0]}, 2.44949 {a where a = 2.44949 [a^2-6=0]}, 2.64575 {a where a = 2.64575 [a^2-7=0]}, 2.82843 {2*a where a = 1.41421 [a^2-2=0]}, 3, 3.16228 {a where a = 3.16228 [a^2-10=0]}]\n", "[2.44949 {a where a = 2.44949 [a^2-6=0]}, 2.64575 {a where a = 2.64575 [a^2-7=0]}, 2.82843 {2*a where a = 1.41421 [a^2-2=0]}, 3, 3.16228 {a where a = 3.16228 [a^2-10=0]}, 3.31662 {a where a = 3.31662 [a^2-11=0]}]" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = ca_mat([[sqrt(i+j+1) for i in range(6)] for j in range(6)])\n", "A" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$-4 a_{1} a_{3} a_{5} a_{6}-20 a_{1} a_{3} a_{5} a_{7}-24 a_{1} a_{3} a_{5}-4 a_{1} a_{3} a_{6} a_{7} + 8 a_{1} a_{3} a_{6} + 136 a_{1} a_{3}-28 a_{1} a_{5} a_{6} a_{7}-116 a_{1} a_{5} a_{6}-88 a_{1} a_{5} a_{7} + 64 a_{1} a_{5} + 112 a_{1} a_{6} a_{7} + 164 a_{1} a_{6}-60 a_{1} a_{7} + 244 a_{1} + 204 a_{3} a_{5} a_{6} a_{7}-96 a_{3} a_{5} a_{6} + 8 a_{3} a_{5} a_{7} + 144 a_{3} a_{5}-152 a_{3} a_{6} a_{7}-240 a_{3} a_{6} + 500 a_{3} a_{7} + 548 a_{3}-216 a_{5} a_{6} a_{7} + 116 a_{5} a_{6} + 628 a_{5} a_{7} + 764 a_{5}-500 a_{6} a_{7} + 24 a_{6}-1440 a_{7}-3868\\; \\text{ where } a_{1} = \\sqrt{11},\\;a_{2} = \\sqrt{10},\\;a_{3} = \\sqrt{7},\\;a_{4} = \\sqrt{6},\\;a_{5} = \\sqrt{5},\\;a_{6} = \\sqrt{3},\\;a_{7} = \\sqrt{2}$$" ], "text/plain": [ "-8.09559e-17 {-4*a*c*e*f-20*a*c*e*g-24*a*c*e-4*a*c*f*g+8*a*c*f+136*a*c-28*a*e*f*g-116*a*e*f-88*a*e*g+64*a*e+112*a*f*g+164*a*f-60*a*g+244*a+204*c*e*f*g-96*c*e*f+8*c*e*g+144*c*e-152*c*f*g-240*c*f+500*c*g+548*c-216*e*f*g+116*e*f+628*e*g+764*e-500*f*g+24*f-1440*g-3868 where a = 3.31662 [a^2-11=0], b = 3.16228 [b^2-10=0], c = 2.64575 [c^2-7=0], d = 2.44949 [d^2-6=0], e = 2.23607 [e^2-5=0], f = 1.73205 [f^2-3=0], g = 1.41421 [g^2-2=0]}" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.det()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Eigenvalues and matrix functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Calcium can calculate exact eigenvalues of matrices, with correct multiplicities. This is accomplished by factoring the characteristic polynomial. Currently, computing polynomial roots will only work for polynomials with very simple structure or with rational entries, so do not expect too much!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/latex": [ "$$\\displaystyle{\\begin{pmatrix}1 & a_{1} \\\\- a_{1} & 1\\end{pmatrix}}\\; \\text{ where } a_{1} = \\pi$$" ], "text/plain": [ "ca_mat of size 2 x 2\n", "[ 1, 3.14159 {a where a = 3.14159 [Pi]}]\n", "[-3.14159 {-a where a = 3.14159 [Pi]}, 1]" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "A = ca_mat([[1,pi],[-pi,1]])\n", "display(A)\n", "\n", "for lamda, mult in A.eigenvalues():\n", " print(\"Multiplicity\", mult)\n", " display(lamda)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We demonstrate computing the Jordan decomposition of a matrix with nontrivial Jordan form:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = ca_mat([[20,77,59,40], [0,-2,-3,-2], [-10,-35,-23,-15], [2,7,3,1]])\n", "J, P = A.jordan_form(transform=True)\n", "display(J)\n", "display(P)\n", "display(P * J * P.inv())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We construct a simple matrix and compute its matrix logarithm, which is uses Jordan decomposition internally:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = ca_mat([[-1, -2], [1, 1]])\n", "display(A)\n", "display(A.log())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We evaluate the exponential of the logarithm, recovering the original matrix. This will only work in very simple cases." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A.log().exp()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another nice example:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "B = ca_mat([[0,0,1],[0,1,0],[1,0,0]])\n", "display(B.log())\n", "display(B.log().exp())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following matrix is nilpotent; its exponential is a polynomial expression of the matrix:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "A = ca_mat([[10,32,3,-13], [-8,-30,-4,11], [25,90,11,-34], [-6,-28,-5,9]])\n", "display(A.exp())\n", "display(A**0 + A**1 + A**2/2 + A**3/6)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We construct the 5x5 Hilbert matrix and check that its eigenvalues satisfy the expected determinant and trace relations:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "H = ca_mat([[ca(1)/(i+j+1) for i in range(5)] for j in range(5)])\n", "H" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "eig = H.eigenvalues()\n", "for c, mult in eig:\n", " display(c)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "display(sum(c * mult for (c, mult) in eig)); display(H.trace())\n", "display(prod(c ** mult for (c, mult) in eig)); display(H.det())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Polynomials\n", "\n", "The `ca_poly` type represents univariate polynomials with `ca` coefficients. We can construct polynomials and do arithmetic:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = ca_poly([0,1])\n", "f = 1 + (2 + ca(2).sqrt() * ca.pi()) * x + 3*x**2\n", "f" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f ** 5" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ca_poly([1,1,1,1,1,1,1,1,1]).integral()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Polynomial division, GCD and other operations work as expected:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "display(f ** 5 // f**4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "display(f**5 % f**4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "(f * (x**2-1)).gcd(f**2 * (x-1))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "(x**2 + ca.pi()**2).gcd(x + ca.i() * ca.pi())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "ca_poly([9,6,7,-28,12]).squarefree_part()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Squarefree factorization\n", "for (fac, mult) in ca_poly([9,6,7,-28,12]).factor_squarefree()[1]:\n", " print(f\"Multiplicity {mult}:\")\n", " display(fac)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finding the roots of a high-degree polynomial:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f = 4*x**7 + 4*x**6 - 11*x**5 - 16*x**4 + x**3 + 15*x**2 + 10*x + 2\n", "\n", "for root, mult in f.roots():\n", " print(f\"Multiplicity {mult}:\")\n", " display(root)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "f(sqrt(2))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.9" } }, "nbformat": 4, "nbformat_minor": 2 } calcium-0.4.1/doc/make.bat000066400000000000000000000014371407704557200153230ustar00rootroot00000000000000@ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=source set BUILDDIR=build if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd calcium-0.4.1/doc/source/000077500000000000000000000000001407704557200152115ustar00rootroot00000000000000calcium-0.4.1/doc/source/_static/000077500000000000000000000000001407704557200166375ustar00rootroot00000000000000calcium-0.4.1/doc/source/_static/ca2.pdf000066400000000000000000000147061407704557200200070ustar00rootroot00000000000000%PDF-1.5 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xm[ˎ8r+>o / = j1b0]7E&JedSz*[]+ϑF_>ӧu|_s_G=ۙk_Ymz/>}*Ol6}W 48-}yi깊%lk;SickdzSE[Ng*2Y'>pV{qYgml_40\>ת2e~Y~&.jB.Ss8T3;F FSNuk/\M抽vԆJzq>ռ侶( 9_q+9QYw2g! |6/V*` ^}G@ưSITȻ5'I^;5Oj98! r.P4i 9UIQ)2sawx~mnj+Tn]M7ř(V2ƷǓY\y=<|QKm)XtJǃJdSnʢU87=KX?zu$>}SmOpQp5-(<GcO.@ ,(])4dfђɠ5֒kU N֠ vwC7 Dڥ`y&'ۜܢ&Kk9K N~a9JBBlkjMlFWpn-\g^ * ǎ!?"}~IԚ0W|C5:(0OQ f6u';p`9ેٛE$Ў_Y@31^`VJ>p@Tʳ7PS[4apLqY_ ;{ Lt9hwҢ,ZLfֈ8͖BQ@b$ Y`pl߳)MZsn˜I&N܎88[!b?vqiig dtbPPsʁ="2E:Q{d/Z jK&*ӈifp/ΎM3 |$ ֑Qø -E>/x`%; cߩ#5)fX? 2BN4;LNcH6*FbLAaʁS7g7v\=}p>ڠS6'1Ws/5?]E.MmDZMjdFGap Y0ХH< x&OH2>9~R{"nGcMZ.q."z1ܸ$ 527cqټeli4fF8xx*jksJy4 j/En`xLZi.3~6Jcc,ZOc/±;J '@pRnފnk]2İ*Y彏MPtx&n3`L%iH:/.;PSD)Hz歃gh)J<• mE]WyK" Q3]}#P99NZPU,&"9dܶ9W-Q6q@c_{uߊFG2K dkW}1f?J{ I/GoӁ&7aů/3cR-1.<υt̴XNY S!^9!#?Y#!7W m9ǩ074.] ;wF%WG/eɤHř(]oT$otUp) ␒=3~ãFsl&ul/t)i#& =i&%!EE#P+R~$H V91@"U Lh)\0c|/@0TA#Ƒ&e~P}39AOV{ےczap11AΠnf: <%l{!h6Ә]TikFwmN;RMiKJۨ H(W;ԠzS%>U 3`EK5h%f8d1:!_8]x3j@Hi# Ff6w6dpaC% "& _f-nY9V>_E{c6By膑9Q-0XE1& ]Y\Uq^*K܋_k0Ň( =řAN1M'z,Ȯ Cbe#|(*14 )̺p LU@ZyD* ET'$4-ʇy2.6[%h;1Ny +K^PF;L` g|y2YUBDž*s$LŽ[Ԟui}`GS x TlyH6 q+HT8H-a}pJ c4.STKȾ0WQTyx UMF2ggp{kQ &5I+F$yK}t;hHxo^'@>t)EE\ C$ T >{Q[|U1?"(z'B#d|&C؎܉P2=)7{xAxe闞LրqWr`PUIG3mi"e]Wۉ9=@2D 299.PWjc0m I#p;0py U t(Qм5!cx(6n~iy &4;T +9TL=8Do(d"v*,Z ]Im:B$Ƽq=;&' c}ARPAnH=Y`7;3qg$67^ ,r$t¦sgXxaUp0Da41x2'CMFCCƟt /OTn<|J7{[>H5THȪlBK$b4rlDl+H^)fJ&Ѝe.z;5h^Wq] "lٯh~R'ny7s - #c6h׃9RL[hZBf㽮n EދiF/3wt_ETu:Bzy^:,s;v='K/$B*Ω1 DՓ5:W؇; AYPcZ $b { 0xb~aK@Xo\&=5IOK+8ռX"70+o } X7[t;6֤")CV%`^|Kp+Ъ"VĖ3 Mnaixdvr.Gh">~Ni3x9JP޷5<`7To!x}| 4y̹G:h)_F,٣/Qf5b=ᛟxe/u8**?gGh+8>x,ԛl peS TQ BUVoa稳uopÅ!\t it*9bV$B/GYg p謂R`ZRTCrɀ{R*`(^@k=) 󺅿?:UM1cl#pUSkqRR!(+Ql{!:ʞ^"rtW>m<3q,>[t-f#.+ xVP`?eʫoY|󉿎wxcl&vE9ypƅ5_f 썡Q hQ(7UiPGsY'kaв# =Îzz]$V Y^u\q1hUT0qmh*8H1Zu|n`f$; +ЗAꥉ`=(VzLlUة.^<+ho}X^beyBgY#V mUȭt!Yu4 :j:d{j6 i%QIzdRWlWݫB[J8P QxkZ[K21;eiJz8rWC{DV uᆚ*޸fz&^[W؅<܅zW9=G1`tqȕ7`ԪIqzU:ؒ鋋鱼 М"Kj94z}ΡSgQ}ps7.:MDJXlEo"5E A+*[x!4r~::?йNb+"ĕ60Wك_ET PFc,5Zcs/*2vJfS6TQC!_TwSE_9Ry Hi΅Y; <CUކ'Hd׫xy`,&#; wHjt՞ Od:# yfb-s}-H8?߿8e9zzlj}둮B;Ctc!=Y3l.[Sz &=ӌg\W mNKHH@N6J(WA C bE*Òn[s1`xP]d>FW6{qFx8 ؽ>xÅu%ܪawɸ:I%|8$ޅ(Mݪ:BS9^7^?W+AVDZ=ϣmG1ӽD^ vWt 4/yįhތ]CA_ ̥7WG {'O%\x`Q{|]TvHkh9 WJ_t "DJEkAg1<4D\j-W^Z(t '{UwhEEpumSV1,"H}`Ju&hb?y.g]-4'ᣵ`c"M?o_3j> endstream endobj 5 0 obj 5706 endobj 3 0 obj << /ExtGState << /a0 << /CA 1 /ca 1 >> >> >> endobj 2 0 obj << /Type /Page % 1 /Parent 1 0 R /MediaBox [ 0 0 74.557747 88.361374 ] /Contents 4 0 R /Group << /Type /Group /S /Transparency /I true /CS /DeviceRGB >> /Resources 3 0 R >> endobj 1 0 obj << /Type /Pages /Kids [ 2 0 R ] /Count 1 >> endobj 6 0 obj << /Producer (cairo 1.15.10 (http://cairographics.org)) /CreationDate (D:20200521175644+02'00) >> endobj 7 0 obj << /Type /Catalog /Pages 1 0 R >> endobj xref 0 8 0000000000 65535 f 0000006123 00000 n 0000005893 00000 n 0000005821 00000 n 0000000015 00000 n 0000005798 00000 n 0000006188 00000 n 0000006304 00000 n trailer << /Size 8 /Root 7 0 R /Info 6 0 R >> startxref 6356 %%EOF calcium-0.4.1/doc/source/_static/ca2.svg000066400000000000000000000475731407704557200200450ustar00rootroot00000000000000 image/svg+xml calcium-0.4.1/doc/source/_static/default.css000066400000000000000000000010011407704557200207650ustar00rootroot00000000000000@import url("classic.css"); @import url('https://fonts.googleapis.com/css?family=Roboto'); div .toctree-wrapper { column-count: 2; } div .toctree-wrapper > ul { margin: 0; } ul .toctree-l1 { margin: 0; -webkit-column-break-inside: avoid; page-break-inside: avoid; break-inside: avoid-column; } div.body { min-width: 450px; max-width: 100%; } li p { margin: 0.2em; } .citation dd { margin-left: 6em; } code { padding: 0.1em; background-color: #f8f8f8; border: 1px solid #eee; } calcium-0.4.1/doc/source/bibliography.rst000066400000000000000000000143571407704557200204300ustar00rootroot00000000000000.. _bibliography: Bibliography ================================================================================ (In the PDF edition, this section is empty. See the bibliography listing at the end of the document.) All referenced works: [BBK2014]_, [BF2020]_, [BFSS2006]_, [Boe2020]_, [Car2004]_, [Cho1999]_, [Coh1996]_, [Coh2000]_, [Fie2007]_, [GCL1992]_, [Har2010]_, [Har2015]_, [Har2018]_, [Joh2017]_, [JR1999]_, [Mos1971]_, [MP2006]_, [RF1994]_, [Ric1992]_, [Ric1995]_, [Ric1997]_, [Ric2007]_, [Ric2009]_, [Ste2002]_, [Ste2010]_, [Str1997]_, [Str2012]_, [vdH1995]_, [vdH2006]_, [vHP2012]_, [Zip1985]_. .. [BBK2014] \D. H. Bailey, J. M. Borwein and A. D. Kaiser. "Automated simplification of large symbolic expressions". Journal of Symbolic Computation Volume 60, January 2014, Pages 120-136. https://doi.org/10.1016/j.jsc.2013.09.001 .. [BF2020] \F. Beukers and J. Forsgård. "Gamma-evaluations of hypergeometric series". Preprint, 2020. https://arxiv.org/abs/2004.08117 .. [BFSS2006] \A. Bostan, P. Flajolet, B. Salvy and É. Schost. "Fast computation of special resultants". Journal of Symbolic Computation, 41(1):1–29, January 2006. https://doi.org/10.1016/j.jsc.2005.07.001 .. [Boe2020] \H. Boehm. "Towards an API for the real numbers". PLDI 2020: Proceedings of the 41st ACM SIGPLAN Conference on Programming Language Design and Implementation, June 2020, Pages 562-576. https://doi.org/10.1145/3385412.3386037 .. [Car2004] \J. Carette. "Understanding expression simplification." ISSAC '04: Proceedings of the 2004 international symposium on Symbolic and algebraic computation, pp. 72-79. 2004. https://doi.org/10.1145/1005285.1005298 .. [Cho1999] \T. Chow. "What is a closed-form number?". The American Mathematical Monthly Volume 106, 1999 - Issue 5. https://doi.org/10.1080/00029890.1999.12005066 .. [Coh1996] \H. Cohen. *A course in computational algebraic number theory*. Third edition, Springer, 1996. https://doi.org/10.1007/978-3-662-02945-9 .. [Coh2000] \H. Cohen. *Advanced topics in computational number theory*. Springer, 2000. https://doi.org/10.1007/978-1-4419-8489-0 .. [Fie2007] \C. Fieker, "Sparse representation for cyclotomic fields". Experiment. Math. Volume 16, Issue 4 (2007), 493-500. https://doi.org/10.1080/10586458.2007.10129012 .. [GCL1992] \K. O. Geddes, S. R. Czapor and G. Labahn. *Algorithms for computer algebra*. Springer, 1992. https://doi.org/10.1007/b102438 .. [Har2010] \W. B. Hart. "Fast library for number theory: an introduction." International Congress on Mathematical Software. Springer, Berlin, Heidelberg, 2010. https://doi.org/10.1007/978-3-642-15582-6_18 .. [Har2015] \W. B. Hart. "ANTIC: Algebraic number theory in C". Computeralgebra-Rundbrief: Vol. 56, 2015 .. [Har2018] \W. B. Hart. "Algebraic number theory". Unpublished manuscript, 2018. .. [Joh2017] \F. Johansson. "Arb: efficient arbitrary-precision midpoint-radius interval arithmetic". IEEE Transactions on Computers, vol 66, issue 8, 2017, pp. 1281-1292. https://doi.org/10.1109/TC.2017.2690633 .. [JR1999] \D. Jeffrey and A. D. Rich. "Simplifying square roots of square roots by denesting". Computer Algebra Systems: A Practical Guide, M.J. Wester, Ed., Wiley 1999. .. [MP2006] \M. Monagan and R. Pearce. "Rational simplification modulo a polynomial ideal". Proceedings of the 2006 international symposium on Symbolic and algebraic computation - ISSAC '06. https://doi.org/10.1145/1145768.1145809 .. [Mos1971] \J. Moses. "Algebraic simplification - a guide for the perplexed". Proceedings of the second ACM symposium on Symbolic and algebraic manipulation (1971), 282-304. https://doi.org/10.1145/362637.362648 .. [RF1994] \D. Richardson and J. Fitch. "The identity problem for elementary functions and constants". ISSAC '94: Proceedings of the international symposium on Symbolic and algebraic computation, August 1994, 285-290. https://doi.org/10.1145/190347.190429 .. [Ric1992] \D. Richardson. "The elementary constant problem". ISSAC '92: Papers from the international symposium on Symbolic and algebraic computation, August 1992, 108-116. https://doi.org/10.1145/143242.143284 .. [Ric1995] \D. Richardson. "A simplified method of recognizing zero among elementary constants". ISSAC '95: Proceedings of the 1995 international symposium on Symbolic and algebraic computation, April 1995, 104-109. https://doi.org/10.1145/220346.220360 .. [Ric1997] \D. Richardson. "How to recognize zero". Journal of Symbolic Computation 24.6 (1997): 627-645. https://doi.org/10.1006/jsco.1997.0157 .. [Ric2007] \D. Richardson. "Zero tests for constants in simple scientific computation". Mathematics in Computer Science volume 1, pages 21-37 (2007). https://doi.org/10.1007/s11786-007-0002-x .. [Ric2009] \D. Richardson. "Recognising zero among implicitly defined elementary numbers". Preprint, 2009. .. [Ste2002] \A. Steel. "A new scheme for computing with algebraically closed fields". In: Fieker C., Kohel D.R. (eds) Algorithmic Number Theory. ANTS 2002. Lecture Notes in Computer Science, vol 2369. Springer, Berlin, Heidelberg. https://doi.org/10.1007/3-540-45455-1_38 .. [Ste2010] \A. Steel. "Computing with algebraically closed fields". Journal of Symbolic Computation 45 (2010) 342-372. https://doi.org/10.1016/j.jsc.2009.09.005 .. [Str1997] \A. Strzebonski. "Computing in the field of complex algebraic numbers". Journal of Symbolic Computation (1997) 24, 647-656. https://doi.org/10.1006/jsco.1997.0158 .. [Str2012] \A. Strzebonski. "Real root isolation for exp-log-arctan functions". Journal of Symbolic Computation 47 (2012) 282–314. https://doi.org/10.1016/j.jsc.2011.11.004 .. [vHP2012] \M. van Hoeij and V. Pal. "Isomorphisms of algebraic number fields". Journal de Théorie des Nombres de Bordeaux, Vol. 24, No. 2 (2012), pp. 293-305. https://doi.org/10.2307/43973105 .. [vdH1995] \J. van der Hoeven, "Automatic numerical expansions". Proc. of the conference Real numbers and computers (1995), 261-274. https://www.texmacs.org/joris/ane/ane-abs.html .. [vdH2006] \J. van der Hoeven, "Computations with effective real numbers". Theoretical Computer Science, Volume 351, Issue 1, 14 February 2006, Pages 52-60. https://doi.org/10.1016/j.tcs.2005.09.060 .. [Zip1985] \R. Zippel. "Simplification of expressions involving radicals". Journal of Symbolic Computation (1985) 1, 189-210. https://doi.org/10.1016/S0747-7171(85)80014-6 calcium-0.4.1/doc/source/ca.rst000066400000000000000000001727721407704557200163460ustar00rootroot00000000000000.. _ca: **ca.h** -- exact real and complex numbers =============================================================================== A :type:`ca_t` represents a real or complex number in a form suitable for exact field arithmetic or comparison. Exceptionally, a :type:`ca_t` may represent a special nonnumerical value, such as an infinity. Introduction: numbers ------------------------------------------------------------------------------- A *Calcium number* is a real or complex number represented as an element of a formal field `K = \mathbb{Q}(a_1, \ldots, a_n)` where the symbols `a_k` denote fixed algebraic or transcendental numbers called *extension numbers*. For example, `e^{-2 \pi} - 3 i` may be represented as `(1 - 3 a_2^2 a_1) / a_2^2` in the field `\mathbb{Q}(a_1,a_2)` with `a_1 = i, a_2 = e^{\pi}`. Extension numbers and fields are documented in the following separate modules: * :ref:`ca-ext` * :ref:`ca-field` The user does not need to construct extension numbers or formal extension fields explicitly: each :type:`ca_t` contains an internal pointer to its formal field, and operations on Calcium numbers generate and cache fields automatically as needed to express the results. This representation is not canonical (in general). A given complex number can be represented in different ways depending on the choice of formal field *K*. Even within a fixed field *K*, a number can have different representations if there are algebraic relations between the extension numbers. Two numbers *x* and *y* can be tested for inequality using numerical evaluation; to test for equality, it may be necessary to eliminate dependencies between extension numbers. One of the central goals of Calcium will be to implement heuristics for such elimination. Together with each formal field *K*, Calcium stores a *reduction ideal* `I = \{g_1,\ldots,g_m\}` with `g_i \in \mathbb{Z}[a_1,\ldots,a_n]`, defining a set of algebraic relations `g_i(a_1,\ldots,a_n) = 0`. Relations can be absolute, say `g_i = a_j^2 + 1`, or relative, say `g_i = 2 a_j - 4 a_k - a_l a_m`. The reduction ideal effectively partitions `K` into equivalence classes of complex numbers (e.g. `i^2 = -1` or `2 \log(\pi i) = 4 \log(\sqrt{\pi}) + \pi i`), enabling simplifications and equality proving. Extension numbers are always sorted `a_1 \succ a_2 \succ \ldots \succ a_n` where `\succ` denotes a structural ordering (see :func:`ca_cmp_repr`). If the reduction ideal is triangular and the multivariate polynomial arithmetic uses lexicographic ordering, reduction by *I* eliminates numbers `a_i` with higher complexity in the sense of `\succ`. The reduction ideal is an imperfect computational crutch: it is not guaranteed to capture *all* algebraic relations, and reduction is not guaranteed to produce uniquely defined representatives. However, in the specific case of an absolute number field `K = \mathbb{Q}(a)` where *a* is a :type:`qqbar_t` extension, the reduction ideal (consisting of a single minimal polynomial) is canonical and field elements of *K* can be chosen canonically. Introduction: special values ------------------------------------------------------------------------------- In order to provide a closed arithmetic system and express limiting cases of operators and special functions, a :type:`ca_t` can hold any of the following special values besides ordinary numbers: * *Unsigned infinity*, a formal object `{\tilde \infty}` representing the value of `1 / 0`. More generally, this is the value of meromorphic functions at poles. * *Signed infinity*, a formal object `a \cdot \infty` where the sign `a` is a Calcium number with `|a| = 1`. The most common values are `+\infty, -\infty, +i \infty, -i \infty`. Signed infinities are used to denote directional limits and logarithmic singularities (for example, `\log(0) = -\infty`). * *Undefined*, a formal object representing the value of indeterminate forms such as `0 / 0` and essential singularities such as `\exp(\tilde \infty)`, where a number or infinity would not make sense as an answer. * *Unknown*, a meta-value used to signal that the actual desired value could not be computed, either because Calcium does not (yet) have a data structure or algorithm for that case, or because doing so would be unreasonably expensive. This occurs, for example, if Calcium performs a division and is unable to decide whether the result is a number, unsigned infinity or undefined (because testing for zero fails). Wrappers may want to check output variables for *Unknown* and throw an exception (e.g. *NotImplementedError* in Python). The distinction between *Calcium numbers* (which must represent elements of `\mathbb{C}`) and the different kinds of nonnumerical values (infinities, Undefined or Unknown) is essential. Nonnumerical values may not be used as field extension numbers `a_k`, and the denominator of a formal field element must always represent a nonzero complex number. Accordingly, for any given Calcium value *x* that is not *Unknown*, it is exactly known whether *x* represents A) a number, B) unsigned infinity, C) a signed infinity, or D) Undefined. Number objects ------------------------------------------------------------------------------- For all types, a *type_t* is defined as an array of length one of type *type_struct*, permitting a *type_t* to be passed by reference. .. type:: ca_struct .. type:: ca_t A :type:`ca_t` contains an index to a field *K*, and data representing an element *x* of *K*. The data is either an inline rational number (:type:`fmpq_t`), an inline Antic number field element (:type:`nf_elem_t`) when *K* is an absolute algebraic number field `\mathbb{Q}(a)`, or a pointer to a heap-allocated :type:`fmpz_mpoly_q_t` representing an element of a generic field `\mathbb{Q}(a_1,\ldots,a_n)`. Special values are encoded using magic bits in the field index. .. type:: ca_ptr Alias for ``ca_struct *``, used for vectors of numbers. .. type:: ca_srcptr Alias for ``const ca_struct *``, used for vectors of numbers when passed as constant input to functions. Context objects ------------------------------------------------------------------------------- .. type:: ca_ctx_struct .. type:: ca_ctx_t A :type:`ca_ctx_t` context object holds a cache of fields *K* and constituent extension numbers `a_k`. The field index in an individual :type:`ca_t` instance represents a shallow reference to the object defining the field *K* within the context object, so creating many elements of the same field is cheap. Since context objects are mutable (and may be mutated even when performing read-only operations on :type:`ca_t` instances), they must not be accessed simultaneously by different threads: in multithreaded environments, the user must use a separate context object for each thread. .. function:: void ca_ctx_init(ca_ctx_t ctx) Initializes the context object *ctx* for use. Any evaluation options stored in the context object are set to default values. .. function:: void ca_ctx_clear(ca_ctx_t ctx) Clears the context object *ctx*, freeing any memory allocated internally. This function should only be called after all :type:`ca_t` instances referring to this context have been cleared. .. function:: void ca_ctx_print(const ca_ctx_t ctx) Prints a description of the context *ctx* to standard output. This will give a complete listing of the cached fields in *ctx*. Memory management for numbers ------------------------------------------------------------------------------- .. function:: void ca_init(ca_t x, ca_ctx_t ctx) Initializes the variable *x* for use, associating it with the context object *ctx*. The value of *x* is set to the rational number 0. .. function:: void ca_clear(ca_t x, ca_ctx_t ctx) Clears the variable *x*. .. function:: void ca_swap(ca_t x, ca_t y, ca_ctx_t ctx) Efficiently swaps the variables *x* and *y*. Symbolic expressions ------------------------------------------------------------------------------- .. function:: void ca_get_fexpr(fexpr_t res, const ca_t x, ulong flags, ca_ctx_t ctx) Sets *res* to a symbolic expression representing *x*. .. function:: int ca_set_fexpr(ca_t res, const fexpr_t expr, ca_ctx_t ctx) Sets *res* to the value represented by the symbolic expression *expr*. Returns 1 on success and 0 on failure. This function essentially just traverses the expression tree using ``ca`` arithmetic; it does not provide advanced symbolic evaluation. It is guaranteed to at least be able to parse the output of :func:`ca_get_fexpr`. .. _ca-printing: Printing ------------------------------------------------------------------------------- The style of printed output is controlled by ``ctx->options[CA_OPT_PRINT_FLAGS]`` (see :ref:`context-options`) which can be set to any combination of the following flags: .. macro:: CA_PRINT_N Print a decimal approximation of the number. The approximation is guaranteed to be correctly rounded to within one unit in the last place. If combined with ``CA_PRINT_REPR``, numbers appearing within the symbolic representation will also be printed with decimal approximations. Warning: printing a decimal approximation requires a computation, which can be expensive. It can also mutate cached data (numerical enclosures of extension numbers), affecting subsequent computations. .. macro:: CA_PRINT_DIGITS Multiplied by a positive integer, specifies the number of decimal digits to show with ``CA_PRINT_N``. If not given, the default precision is six digits. .. macro:: CA_PRINT_REPR Print the symbolic representation of the number (including its recursive elements). If used together with ``CA_PRINT_N``, field elements will print as ``decimal {symbolic}`` while extension numbers will print as ``decimal [symbolic]``. All extension numbers appearing in the field defining ``x`` and in the inner constructions of those extension numbers will be given local labels ``a``, ``b``, etc. for this printing. .. macro:: CA_PRINT_FIELD For each field element, explicitly print its formal field along with its reduction ideal if present, e.g. ``QQ`` or ``QQ(a,b,c) / ``. .. macro:: CA_PRINT_DEFAULT The default print style. Equivalent to ``CA_PRINT_N | CA_PRINT_REPR``. .. macro:: CA_PRINT_DEBUG Verbose print style for debugging. Equivalent to ``CA_PRINT_N | CA_PRINT_REPR | CA_PRINT_FIELD``. As a special case, small integers are always printed as simple literals. As illustration, here are the numbers `-7`, `2/3`, `(\sqrt{3}+5)/2` and `\sqrt{2} (\log(\pi) + \pi i)` printed in various styles:: # CA_PRINT_DEFAULT -7 0.666667 {2/3} 3.36603 {(a+5)/2 where a = 1.73205 [a^2-3=0]} 1.61889 + 4.44288*I {a*c+b*c*d where a = 1.14473 [Log(3.14159 {b})], b = 3.14159 [Pi], c = 1.41421 [c^2-2=0], d = I [d^2+1=0]} # CA_PRINT_N -7 0.666667 3.36603 1.61889 + 4.44288*I # CA_PRINT_N | (CA_PRINT_DIGITS * 20) -7 0.66666666666666666667 3.3660254037844386468 1.6188925298220266685 + 4.4428829381583662470*I # CA_PRINT_REPR -7 2/3 (a+5)/2 where a = [a^2-3=0] a*c+b*c*d where a = Log(b), b = Pi, c = [c^2-2=0], d = [d^2+1=0] # CA_PRINT_DEBUG -7 0.666667 {2/3 in QQ} 3.36603 {(a+5)/2 in QQ(a)/ where a = 1.73205 [a^2-3=0]} 1.61889 + 4.44288*I {a*c+b*c*d in QQ(a,b,c,d)/ where a = 1.14473 [Log(3.14159 {b in QQ(b)})], b = 3.14159 [Pi], c = 1.41421 [c^2-2=0], d = I [d^2+1=0]} .. function:: void ca_print(const ca_t x, const ca_ctx_t ctx) Prints *x* to standard output. .. function:: void ca_fprint(FILE * fp, const ca_t x, const ca_ctx_t ctx) Prints *x* to the file *fp*. .. function:: char * ca_get_str(const ca_t x, const ca_ctx_t ctx) Prints *x* to a string which is returned. The user should free this string by calling ``flint_free``. .. function:: void ca_printn(const ca_t x, slong n, const ca_ctx_t ctx) Prints an *n*-digit numerical representation of *x* to standard output. Special values ------------------------------------------------------------------------------- .. function:: void ca_zero(ca_t res, ca_ctx_t ctx) void ca_one(ca_t res, ca_ctx_t ctx) void ca_neg_one(ca_t res, ca_ctx_t ctx) Sets *res* to the integer 0, 1 or -1. This creates a canonical representation of this number as an element of the trivial field `\mathbb{Q}`. .. function:: void ca_i(ca_t res, ca_ctx_t ctx) void ca_neg_i(ca_t res, ca_ctx_t ctx) Sets *res* to the imaginary unit `i = \sqrt{-1}`, or its negation `-i`. This creates a canonical representation of `i` as the generator of the algebraic number field `\mathbb{Q}(i)`. .. function:: void ca_pi(ca_t res, ca_ctx_t ctx) Sets *res* to the constant `\pi`. This creates an element of the transcendental number field `\mathbb{Q}(\pi)`. .. function:: void ca_pi_i(ca_t res, ca_ctx_t ctx) Sets *res* to the constant `\pi i`. This creates an element of the composite field `\mathbb{Q}(i,\pi)` rather than representing `\pi i` (or even `2 \pi i`, which for some purposes would be more elegant) as an atomic quantity. .. function:: void ca_euler(ca_t res, ca_ctx_t ctx) Sets *res* to Euler's constant `\gamma`. This creates an element of the (transcendental?) number field `\mathbb{Q}(\gamma)`. .. function:: void ca_unknown(ca_t res, ca_ctx_t ctx) Sets *res* to the meta-value *Unknown*. .. function:: void ca_undefined(ca_t res, ca_ctx_t ctx) Sets *res* to *Undefined*. .. function:: void ca_uinf(ca_t res, ca_ctx_t ctx) Sets *res* to unsigned infinity `{\tilde \infty}`. .. function:: void ca_pos_inf(ca_t res, ca_ctx_t ctx) void ca_neg_inf(ca_t res, ca_ctx_t ctx) void ca_pos_i_inf(ca_t res, ca_ctx_t ctx) void ca_neg_i_inf(ca_t res, ca_ctx_t ctx) Sets *res* to the signed infinity `+\infty`, `-\infty`, `+i \infty` or `-i \infty`. Assignment and conversion ------------------------------------------------------------------------------- .. function:: void ca_set(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to a copy of *x*. .. function:: void ca_set_si(ca_t res, slong v, ca_ctx_t ctx) void ca_set_ui(ca_t res, ulong v, ca_ctx_t ctx) void ca_set_fmpz(ca_t res, const fmpz_t v, ca_ctx_t ctx) void ca_set_fmpq(ca_t res, const fmpq_t v, ca_ctx_t ctx) Sets *res* to the integer or rational number *v*. This creates a canonical representation of this number as an element of the trivial field `\mathbb{Q}`. .. function:: void ca_set_d(ca_t res, double x, ca_ctx_t ctx) void ca_set_d_d(ca_t res, double x, double y, ca_ctx_t ctx) Sets *res* to the value of *x*, or the complex value `x + yi`. NaN is interpreted as *Unknown* (not *Undefined*). .. function:: void ca_transfer(ca_t res, ca_ctx_t res_ctx, const ca_t src, ca_ctx_t src_ctx) Sets *res* to *src* where the corresponding context objects *res_ctx* and *src_ctx* may be different. This operation preserves the mathematical value represented by *src*, but may result in a different internal representation depending on the settings of the context objects. Conversion of algebraic numbers ------------------------------------------------------------------------------- .. function:: void ca_set_qqbar(ca_t res, const qqbar_t x, ca_ctx_t ctx) Sets *res* to the algebraic number *x*. If *x* is rational, *res* is set to the canonical representation as an element in the trivial field `\mathbb{Q}`. If *x* is irrational, this function always sets *res* to an element of a univariate number field `\mathbb{Q}(a)`. It will not, for example, identify `\sqrt{2} + \sqrt{3}` as an element of `\mathbb{Q}(\sqrt{2}, \sqrt{3})`. However, it may attempt to find a simpler number field than that generated by *x* itself. For example: * If *x* is quadratic, it will be expressed as an element of `\mathbb{Q}(\sqrt{N})` where *N* has no small repeated factors (obtained by performing a smooth factorization of the discriminant). * TODO: if possible, coerce *x* to a low-degree cyclotomic field. .. function:: int ca_get_fmpz(fmpz_t res, const ca_t x, ca_ctx_t ctx) int ca_get_fmpq(fmpz_t res, const ca_t x, ca_ctx_t ctx) int ca_get_qqbar(qqbar_t res, const ca_t x, ca_ctx_t ctx) Attempts to evaluate *x* to an explicit integer, rational or algebraic number. If successful, sets *res* to this number and returns 1. If unsuccessful, returns 0. The conversion certainly fails if *x* does not represent an integer, rational or algebraic number (respectively), but can also fail if *x* is too expensive to compute under the current evaluation limits. In particular, the evaluation will be aborted if an intermediate algebraic number (or more precisely, the resultant polynomial prior to factorization) exceeds ``CA_OPT_QQBAR_DEG_LIMIT`` or the coefficients exceed some multiple of ``CA_OPT_PREC_LIMIT``. Note that evaluation may hit those limits even if the minimal polynomial for *x* itself is small. The conversion can also fail if no algorithm has been implemented for the functions appearing in the construction of *x*. .. function:: int ca_can_evaluate_qqbar(const ca_t x, ca_ctx_t ctx) Checks if :func:`ca_get_qqbar` has a chance to succeed. In effect, this checks if all extension numbers are manifestly algebraic numbers (without doing any evaluation). Random generation ------------------------------------------------------------------------------- .. function:: void ca_randtest_rational(ca_t res, flint_rand_t state, slong bits, ca_ctx_t ctx) Sets *res* to a random rational number with numerator and denominator up to *bits* bits in size. .. function:: void ca_randtest(ca_t res, flint_rand_t state, slong depth, slong bits, ca_ctx_t ctx) Sets *res* to a random number generated by evaluating a random expression. The algorithm randomly selects between generating a "simple" number (a random rational number or quadratic field element with coefficients up to *bits* in size, or a random builtin constant), or if *depth* is nonzero, applying a random arithmetic operation or function to operands produced through recursive calls with *depth* - 1. The output is guaranteed to be a number, not a special value. .. function:: void ca_randtest_special(ca_t res, flint_rand_t state, slong depth, slong bits, ca_ctx_t ctx) Randomly generates either a special value or a number. .. function:: void ca_randtest_same_nf(ca_t res, flint_rand_t state, const ca_t x, slong bits, slong den_bits, ca_ctx_t ctx) Sets *res* to a random element in the same number field as *x*, with numerator coefficients up to *bits* in size and denominator up to *den_bits* in size. This function requires that *x* is an element of an absolute number field. Representation properties ------------------------------------------------------------------------------- The following functions deal with the representation of a :type:`ca_t` and hence can always be decided quickly and unambiguously. The return value for predicates is 0 for false and 1 for true. .. function:: int ca_equal_repr(const ca_t x, const ca_t y, ca_ctx_t ctx) Returns whether *x* and *y* have identical representation. For field elements, this checks if *x* and *y* belong to the same formal field (with generators having identical representation) and are represented by the same rational function within that field. For special values, this tests equality of the special values, with *Unknown* handled as if it were a value rather than a meta-value: that is, *Unknown* = *Unknown* gives 1, and *Unknown* = *y* gives 0 for any other kind of value *y*. If neither *x* nor *y* is *Unknown*, then representation equality implies that *x* and *y* describe to the same mathematical value, but if either operand is *Unknown*, the result is meaningless for mathematical comparison. .. function:: int ca_cmp_repr(const ca_t x, const ca_t y, ca_ctx_t ctx) Compares the representations of *x* and *y* in a canonical sort order, returning -1, 0 or 1. This only performs a lexicographic comparison of the representations of *x* and *y*; the return value does not say anything meaningful about the numbers represented by *x* and *y*. .. function:: ulong ca_hash_repr(const ca_t x, ca_ctx_t ctx) Hashes the representation of *x*. .. function:: int ca_is_unknown(const ca_t x, ca_ctx_t ctx) Returns whether *x* is Unknown. .. function:: int ca_is_special(const ca_t x, ca_ctx_t ctx) Returns whether *x* is a special value or metavalue (not a field element). .. function:: int ca_is_qq_elem(const ca_t x, ca_ctx_t ctx) Returns whether *x* is represented as an element of the rational field `\mathbb{Q}`. .. function:: int ca_is_qq_elem_zero(const ca_t x, ca_ctx_t ctx) int ca_is_qq_elem_one(const ca_t x, ca_ctx_t ctx) int ca_is_qq_elem_integer(const ca_t x, ca_ctx_t ctx) Returns whether *x* is represented as the element 0, 1 or any integer in the rational field `\mathbb{Q}`. .. function:: int ca_is_nf_elem(const ca_t x, ca_ctx_t ctx) Returns whether *x* is represented as an element of a univariate algebraic number field `\mathbb{Q}(a)`. .. function:: int ca_is_cyclotomic_nf_elem(slong * p, ulong * q, const ca_t x, ca_ctx_t ctx) Returns whether *x* is represented as an element of a univariate cyclotomic field, i.e. `\mathbb{Q}(a)` where *a* is a root of unity. If *p* and *q* are not *NULL* and *x* is represented as an element of a cyclotomic field, this also sets *p* and *q* to the minimal integers with `0 \le p < q` such that the generating root of unity is `a = e^{2 \pi i p / q}`. Note that the answer 0 does not prove that *x* is not a cyclotomic number, and the order *q* is also not necessarily the generator of the *smallest* cyclotomic field containing *x*. For the purposes of this function, only nontrivial cyclotomic fields count; the return value is 0 if *x* is represented as a rational number. .. function:: int ca_is_generic_elem(const ca_t x, ca_ctx_t ctx) Returns whether *x* is represented as a generic field element; i.e. it is not a special value, not represented as an element of the rational field, and not represented as an element of a univariate algebraic number field. Value predicates ------------------------------------------------------------------------------- The following predicates check a mathematical property which might not be effectively decidable. The result is a :type:`truth_t` to allow representing an unknown outcome. .. function:: truth_t ca_check_is_number(const ca_t x, ca_ctx_t ctx) Tests if *x* is a number. The result is ``T_TRUE`` is *x* is a field element (and hence a complex number), ``T_FALSE`` if *x* is an infinity or *Undefined*, and ``T_UNKNOWN`` if *x* is *Unknown*. .. function:: truth_t ca_check_is_zero(const ca_t x, ca_ctx_t ctx) truth_t ca_check_is_one(const ca_t x, ca_ctx_t ctx) truth_t ca_check_is_neg_one(const ca_t x, ca_ctx_t ctx) truth_t ca_check_is_i(const ca_t x, ca_ctx_t ctx) truth_t ca_check_is_neg_i(const ca_t x, ca_ctx_t ctx) Tests if *x* is equal to the number `0`, `1`, `-1`, `i`, or `-i`. .. function:: truth_t ca_check_is_algebraic(const ca_t x, ca_ctx_t ctx) truth_t ca_check_is_rational(const ca_t x, ca_ctx_t ctx) truth_t ca_check_is_integer(const ca_t x, ca_ctx_t ctx) Tests if *x* is respectively an algebraic number, a rational number, or an integer. .. function:: truth_t ca_check_is_real(const ca_t x, ca_ctx_t ctx) Tests if *x* is a real number. Warning: this returns ``T_FALSE`` if *x* is an infinity with real sign. .. function:: truth_t ca_check_is_negative_real(const ca_t x, ca_ctx_t ctx) Tests if *x* is a negative real number. Warning: this returns ``T_FALSE`` if *x* is negative infinity. .. function:: truth_t ca_check_is_imaginary(const ca_t x, ca_ctx_t ctx) Tests if *x* is an imaginary number. Warning: this returns ``T_FALSE`` if *x* is an infinity with imaginary sign. .. function:: truth_t ca_check_is_undefined(const ca_t x, ca_ctx_t ctx) Tests if *x* is the special value *Undefined*. .. function:: truth_t ca_check_is_infinity(const ca_t x, ca_ctx_t ctx) Tests if *x* is any infinity (unsigned or signed). .. function:: truth_t ca_check_is_uinf(const ca_t x, ca_ctx_t ctx) Tests if *x* is unsigned infinity `{\tilde \infty}`. .. function:: truth_t ca_check_is_signed_inf(const ca_t x, ca_ctx_t ctx) Tests if *x* is any signed infinity. .. function:: truth_t ca_check_is_pos_inf(const ca_t x, ca_ctx_t ctx) truth_t ca_check_is_neg_inf(const ca_t x, ca_ctx_t ctx) truth_t ca_check_is_pos_i_inf(const ca_t x, ca_ctx_t ctx) truth_t ca_check_is_neg_i_inf(const ca_t x, ca_ctx_t ctx) Tests if *x* is equal to the signed infinity `+\infty`, `-\infty`, `+i \infty`, `-i \infty`, respectively. Comparisons ------------------------------------------------------------------------------- .. function:: truth_t ca_check_equal(const ca_t x, const ca_t y, ca_ctx_t ctx) Tests `x = y` as a mathematical equality. The result is ``T_UNKNOWN`` if either operand is *Unknown*. The result may also be ``T_UNKNOWN`` if *x* and *y* are numerically indistinguishable and cannot be proved equal or unequal by an exact computation. .. function:: truth_t ca_check_lt(const ca_t x, const ca_t y, ca_ctx_t ctx) truth_t ca_check_le(const ca_t x, const ca_t y, ca_ctx_t ctx) truth_t ca_check_gt(const ca_t x, const ca_t y, ca_ctx_t ctx) truth_t ca_check_ge(const ca_t x, const ca_t y, ca_ctx_t ctx) Compares *x* and *y*, implementing the respective operations `x < y`, `x \le y`, `x > y`, `x \ge y`. Only real numbers and `-\infty` and `+\infty` are considered comparable. The result is ``T_FALSE`` (not ``T_UNKNOWN``) if either operand is not comparable (being a nonreal complex number, unsigned infinity, or undefined). Field structure operations ------------------------------------------------------------------------------- .. function:: void ca_merge_fields(ca_t resx, ca_t resy, const ca_t x, const ca_t y, ca_ctx_t ctx) Sets *resx* and *resy* to copies of *x* and *y* coerced to a common field. Both *x* and *y* must be field elements (not special values). In the present implementation, this simply merges the lists of generators, avoiding duplication. In the future, it will be able to eliminate generators satisfying algebraic relations. .. function:: void ca_condense_field(ca_t res, ca_ctx_t ctx) Attempts to demote the value of *res* to a trivial subfield of its current field by removing unused generators. In particular, this demotes any obviously rational value to the trivial field `\mathbb{Q}`. This function is applied automatically in most operations (arithmetic operations, etc.). .. function:: ca_ext_ptr ca_is_gen_as_ext(const ca_t x, ca_ctx_t ctx) If *x* is a generator of its formal field, `x = a_k \in \mathbb{Q}(a_1,\ldots,a_n)`, returns a pointer to the extension number defining `a_k`. If *x* is not a generator, returns *NULL*. Arithmetic ------------------------------------------------------------------------------- .. function:: void ca_neg(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the negation of *x*. For numbers, this operation amounts to a direct negation within the formal field. For a signed infinity `c \infty`, negation gives `(-c) \infty`; all other special values are unchanged. .. function:: void ca_add_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx) void ca_add_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx) void ca_add_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx) void ca_add_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx) void ca_add(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) Sets *res* to the sum of *x* and *y*. For special values, the following rules apply (`c \infty` denotes a signed infinity, `|c| = 1`): * `c \infty + d \infty = c \infty` if `c = d` * `c \infty + d \infty = \text{Undefined}` if `c \ne d` * `\tilde \infty + c \infty = \tilde \infty + \tilde \infty = \text{Undefined}` * `c \infty + z = c \infty` if `z \in \mathbb{C}` * `\tilde \infty + z = \tilde \infty` if `z \in \mathbb{C}` * `z + \text{Undefined} = \text{Undefined}` for any value *z* (including *Unknown*) In any other case involving special values, or if the specific case cannot be distinguished, the result is *Unknown*. .. function:: void ca_sub_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx) void ca_sub_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx) void ca_sub_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx) void ca_sub_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx) void ca_fmpq_sub(ca_t res, const fmpq_t x, const ca_t y, ca_ctx_t ctx) void ca_fmpz_sub(ca_t res, const fmpz_t x, const ca_t y, ca_ctx_t ctx) void ca_ui_sub(ca_t res, ulong x, const ca_t y, ca_ctx_t ctx) void ca_si_sub(ca_t res, slong x, const ca_t y, ca_ctx_t ctx) void ca_sub(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) Sets *res* to the difference of *x* and *y*. This is equivalent to computing `x + (-y)`. .. function:: void ca_mul_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx) void ca_mul_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx) void ca_mul_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx) void ca_mul_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx) void ca_mul(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) Sets *res* to the product of *x* and *y*. For special values, the following rules apply (`c \infty` denotes a signed infinity, `|c| = 1`): * `c \infty \cdot d \infty = c d \infty` * `c \infty \cdot \tilde \infty = \tilde \infty` * `\tilde \infty \cdot \tilde \infty = \tilde \infty` * `c \infty \cdot z = \operatorname{sgn}(z) c \infty` if `z \in \mathbb{C} \setminus \{0\}` * `c \infty \cdot 0 = \text{Undefined}` * `\tilde \infty \cdot 0 = \text{Undefined}` * `z \cdot \text{Undefined} = \text{Undefined}` for any value *z* (including *Unknown*) In any other case involving special values, or if the specific case cannot be distinguished, the result is *Unknown*. .. function:: void ca_inv(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the multiplicative inverse of *x*. In a univariate algebraic number field, this always produces a rational denominator, but the denominator might not be rationalized in a multivariate field. For special values and zero, the following rules apply: * `1 / (c \infty) = 1 / \tilde \infty = 0` * `1 / 0 = \tilde \infty` * `1 / \text{Undefined} = \text{Undefined}` * `1 / \text{Unknown} = \text{Unknown}` If it cannot be determined whether *x* is zero or nonzero, the result is *Unknown*. .. function:: void ca_fmpq_div(ca_t res, const fmpq_t x, const ca_t y, ca_ctx_t ctx) void ca_fmpz_div(ca_t res, const fmpz_t x, const ca_t y, ca_ctx_t ctx) void ca_ui_div(ca_t res, ulong x, const ca_t y, ca_ctx_t ctx) void ca_si_div(ca_t res, slong x, const ca_t y, ca_ctx_t ctx) void ca_div_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx) void ca_div_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx) void ca_div_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx) void ca_div_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx) void ca_div(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) Sets *res* to the quotient of *x* and *y*. This is equivalent to computing `x \cdot (1 / y)`. For special values and division by zero, this implies the following rules (`c \infty` denotes a signed infinity, `|c| = 1`): * `(c \infty) / (d \infty) = (c \infty) / \tilde \infty = \tilde \infty / (c \infty) = \tilde \infty / \tilde \infty = \text{Undefined}` * `c \infty / z = (c / \operatorname{sgn}(z)) \infty` if `z \in \mathbb{C} \setminus \{0\}` * `c \infty / 0 = \tilde \infty / 0 = \tilde \infty` * `z / (c \infty) = z / \tilde \infty = 0` if `z \in \mathbb{C}` * `z / 0 = \tilde \infty` if `z \in \mathbb{C} \setminus \{0\}` * `0 / 0 = \text{Undefined}` * `z / \text{Undefined} = \text{Undefined}` for any value *z* (including *Unknown*) * `\text{Undefined} / z = \text{Undefined}` for any value *z* (including *Unknown*) In any other case involving special values, or if the specific case cannot be distinguished, the result is *Unknown*. .. function:: void ca_dot(ca_t res, const ca_t initial, int subtract, ca_srcptr x, slong xstep, ca_srcptr y, slong ystep, slong len, ca_ctx_t ctx) Computes the dot product of the vectors *x* and *y*, setting *res* to `s + (-1)^{subtract} \sum_{i=0}^{len-1} x_i y_i`. The initial term *s* is optional and can be omitted by passing *NULL* (equivalently, `s = 0`). The parameter *subtract* must be 0 or 1. The length *len* is allowed to be negative, which is equivalent to a length of zero. The parameters *xstep* or *ystep* specify a step length for traversing subsequences of the vectors *x* and *y*; either can be negative to step in the reverse direction starting from the initial pointer. Aliasing is allowed between *res* and *s* but not between *res* and the entries of *x* and *y*. .. function:: void ca_fmpz_poly_evaluate(ca_t res, const fmpz_poly_t poly, const ca_t x, ca_ctx_t ctx) void ca_fmpq_poly_evaluate(ca_t res, const fmpq_poly_t poly, const ca_t x, ca_ctx_t ctx) Sets *res* to the polynomial *poly* evaluated at *x*. .. function:: void ca_fmpz_mpoly_evaluate_horner(ca_t res, const fmpz_mpoly_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx) void ca_fmpz_mpoly_evaluate_iter(ca_t res, const fmpz_mpoly_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx) void ca_fmpz_mpoly_evaluate(ca_t res, const fmpz_mpoly_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx) Sets *res* to the multivariate polynomial *f* evaluated at the vector of arguments *x*. .. function:: void ca_fmpz_mpoly_q_evaluate(ca_t res, const fmpz_mpoly_q_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx) Sets *res* to the multivariate rational function *f* evaluated at the vector of arguments *x*. .. function:: void ca_fmpz_mpoly_q_evaluate_no_division_by_zero(ca_t res, const fmpz_mpoly_q_t f, ca_srcptr x, const fmpz_mpoly_ctx_t mctx, ca_ctx_t ctx) void ca_inv_no_division_by_zero(ca_t res, const ca_t x, ca_ctx_t ctx) These functions behave like the normal arithmetic functions, but assume (and do not check) that division by zero cannot occur. Division by zero will result in undefined behavior. Powers and roots ------------------------------------------------------------------------------- .. function:: void ca_sqr(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the square of *x*. .. function:: void ca_pow_fmpq(ca_t res, const ca_t x, const fmpq_t y, ca_ctx_t ctx) void ca_pow_fmpz(ca_t res, const ca_t x, const fmpz_t y, ca_ctx_t ctx) void ca_pow_ui(ca_t res, const ca_t x, ulong y, ca_ctx_t ctx) void ca_pow_si(ca_t res, const ca_t x, slong y, ca_ctx_t ctx) void ca_pow(ca_t res, const ca_t x, const ca_t y, ca_ctx_t ctx) Sets *res* to *x* raised to the power *y*. Handling of special values is not yet implemented. .. function:: void ca_pow_si_arithmetic(ca_t res, const ca_t x, slong n, ca_ctx_t ctx) Sets *res* to *x* raised to the power *n*. Whereas :func:`ca_pow`, :func:`ca_pow_si` etc. may create `x^n` as an extension number if *n* is large, this function always perform the exponentiation using field arithmetic. .. function:: void ca_sqrt_inert(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_sqrt_nofactor(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_sqrt_factor(ca_t res, const ca_t x, ulong flags, ca_ctx_t ctx) void ca_sqrt(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the principal square root of *x*. For special values, the following definitions apply: * `\sqrt{c \infty} = \sqrt{c} \infty` * `\sqrt{\tilde \infty} = \tilde \infty`. * Both *Undefined* and *Unknown* map to themselves. The *inert* version outputs the generator in the formal field `\mathbb{Q}(\sqrt{x})` without simplifying. The *factor* version writes `x = A^2 B` in `K` where `K` is the field of *x*, and outputs `A \sqrt{B}` or `-A \sqrt{B}` (whichever gives the correct sign) as an element of `K(\sqrt{B})` or some subfield thereof. This factorization is only a heuristic and is not guaranteed to make `B` minimal. Factorization options can be passed through to *flags*: see :func:`ca_factor` for details. The *nofactor* version will not perform a general factorization, but may still perform other simplifications. It may in particular attempt to simplify `\sqrt{x}` to a single element in `\overline{\mathbb{Q}}`. .. function:: void ca_sqrt_ui(ca_t res, ulong n, ca_ctx_t ctx) Sets *res* to the principal square root of *n*. Complex parts ------------------------------------------------------------------------------- .. function:: void ca_abs(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the absolute value of *x*. For special values, the following definitions apply: * `|c \infty| = |\tilde \infty| = +\infty`. * Both *Undefined* and *Unknown* map to themselves. This function will attempt to simplify its argument through an exact computation. It may in particular attempt to simplify `|x|` to a single element in `\overline{\mathbb{Q}}`. In the generic case, this function outputs an element of the formal field `\mathbb{Q}(|x|)`. .. function:: void ca_sgn(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the sign of *x*, defined by .. math :: \operatorname{sgn}(x) = \begin{cases} 0 & x = 0 \\ \frac{x}{|x|} & x \ne 0 \end{cases} for numbers. For special values, the following definitions apply: * `\operatorname{sgn}(c \infty) = c`. * `\operatorname{sgn}(\tilde \infty) = \operatorname{Undefined}`. * Both *Undefined* and *Unknown* map to themselves. This function will attempt to simplify its argument through an exact computation. It may in particular attempt to simplify `\operatorname{sgn}(x)` to a single element in `\overline{\mathbb{Q}}`. In the generic case, this function outputs an element of the formal field `\mathbb{Q}(\operatorname{sgn}(x))`. .. function:: void ca_csgn(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the extension of the real sign function taking the value 1 for *z* strictly in the right half plane, -1 for *z* strictly in the left half plane, and the sign of the imaginary part when *z* is on the imaginary axis. Equivalently, `\operatorname{csgn}(z) = z / \sqrt{z^2}` except that the value is 0 when *z* is exactly zero. This function gives *Undefined* for unsigned infinity and `\operatorname{csgn}(\operatorname{sgn}(c \infty)) = \operatorname{csgn}(c)` for signed infinities. .. function:: void ca_arg(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the complex argument (phase) of *x*, normalized to the range `(-\pi, +\pi]`. The argument of 0 is defined as 0. For special values, the following definitions apply: * `\operatorname{arg}(c \infty) = \operatorname{arg}(c)`. * `\operatorname{arg}(\tilde \infty) = \operatorname{Undefined}`. * Both *Undefined* and *Unknown* map to themselves. .. function:: void ca_re(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the real part of *x*. The result is *Undefined* if *x* is any infinity (including a real infinity). .. function:: void ca_im(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the imaginary part of *x*. The result is *Undefined* if *x* is any infinity (including an imaginary infinity). .. function:: void ca_conj_deep(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_conj_shallow(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_conj(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the complex conjugate of *x*. The *shallow* version creates a new extension element `\overline{x}` unless *x* can be trivially conjugated in-place in the existing field. The *deep* version recursively conjugates the extension numbers in the field of *x*. .. function:: void ca_floor(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the floor function of *x*. The result is *Undefined* if *x* is any infinity (including a real infinity). For complex numbers, this is presently defined to take the floor of the real part. .. function:: void ca_ceil(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the ceiling function of *x*. The result is *Undefined* if *x* is any infinity (including a real infinity). For complex numbers, this is presently defined to take the ceiling of the real part. Exponentials and logarithms ------------------------------------------------------------------------------- .. function:: void ca_exp(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the exponential function of *x*. For special values, the following definitions apply: * `e^{+\infty} = +\infty` * `e^{c \infty} = \tilde \infty` if `0 < \operatorname{Re}(c) < 1`. * `e^{c \infty} = 0` if `\operatorname{Re}(c) < 0`. * `e^{c \infty} = \text{Undefined}` if `\operatorname{Re}(c) = 0`. * `e^{\tilde \infty} = \text{Undefined}`. * Both *Undefined* and *Unknown* map to themselves. The following symbolic simplifications are performed automatically: * `e^0 = 1` * `e^{\log(z)} = z` * `e^{(p/q) \log(z)} = z^{p/q}` (for rational `p/q`) * `e^{(p/q) \pi i}` = algebraic root of unity (for small rational `p/q`) In the generic case, this function outputs an element of the formal field `\mathbb{Q}(e^x)`. .. function:: void ca_log(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the natural logarithm of *x*. For special values and at the origin, the following definitions apply: * For any infinity, `\log(c\infty) = \log(\tilde \infty) = +\infty`. * `\log(0) = -\infty`. The result is *Unknown* if deciding `x = 0` fails. * Both *Undefined* and *Unknown* map to themselves. The following symbolic simplifications are performed automatically: * `\log(1) = 0` * `\log\left(e^z\right) = z + 2 \pi i k` * `\log\left(\sqrt{z}\right) = \tfrac{1}{2} \log(z) + 2 \pi i k` * `\log\left(z^a\right) = a \log(z) + 2 \pi i k` * `\log(x) = \log(-x) + \pi i` for negative real *x* In the generic case, this function outputs an element of the formal field `\mathbb{Q}(\log(x))`. Trigonometric functions ------------------------------------------------------------------------------- .. function:: void ca_sin_cos_exponential(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx) void ca_sin_cos_direct(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx) void ca_sin_cos_tangent(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx) void ca_sin_cos(ca_t res1, ca_t res2, const ca_t x, ca_ctx_t ctx) Sets *res1* to the sine of *x* and *res2* to the cosine of *x*. Either *res1* or *res2* can be *NULL* to compute only the other function. Various representations are implemented: * The *exponential* version expresses the sine and cosine in terms of complex exponentials. Simple algebraic values will simplify to rational numbers or elements of cyclotomic fields. * The *direct* method expresses the sine and cosine in terms of the original functions (perhaps after applying some symmetry transformations, which may interchange sin and cos). Extremely simple algebraic values will automatically simplify to elements of real algebraic number fields. * The *tangent* version expresses the sine and cosine in terms of `\tan(x/2)`, perhaps after applying some symmetry transformations. Extremely simple algebraic values will automatically simplify to elements of real algebraic number fields. By default, the standard function uses the *exponential* representation as this typically works best for field arithmetic and simplifications, although it has the disadvantage of introducing complex numbers where real numbers would be sufficient. The behavior of the standard function can be changed using the :macro:`CA_OPT_TRIG_FORM` context setting. For special values, the following definitions apply: * `\sin(\pm i \infty) = \pm i \infty` * `\cos(\pm i \infty) = +\infty` * All other infinities give `\operatorname{Undefined}` .. function:: void ca_sin(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_cos(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the sine or cosine of *x*. These functions are shortcuts for :func:`ca_sin_cos`. .. function:: void ca_tan_sine_cosine(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_tan_exponential(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_tan_direct(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_tan(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the tangent of *x*. The *sine_cosine* version evaluates the tangent as a quotient of a sine and cosine, the *direct* version evaluates it directly as a tangent (possibly after transforming the variable), and the *exponential* version evaluates it in terms of complex exponentials. Simple algebraic values will automatically simplify to elements of trigonometric or cyclotomic number fields. By default, the standard function uses the *exponential* representation as this typically works best for field arithmetic and simplifications, although it has the disadvantage of introducing complex numbers where real numbers would be sufficient. The behavior of the standard function can be changed using the :macro:`CA_OPT_TRIG_FORM` context setting. For special values, the following definitions apply: * At poles, `\tan((n+\tfrac{1}{2}) \pi) = \tilde \infty` * `\tan(e^{i \theta} \infty) = +i, \quad 0 < \theta < \pi` * `\tan(e^{i \theta} \infty) = -i, \quad -\pi < \theta < 0` * `\tan(\pm \infty) = \tan(\tilde \infty) = \operatorname{Undefined}` .. function:: void ca_cot(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the cotangent *x*. This is equivalent to computing the reciprocal of the tangent. .. function:: void ca_atan_logarithm(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_atan_direct(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_atan(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the inverse tangent of *x*. The *direct* version expresses the result as an inverse tangent (possibly after transforming the variable). The *logarithm* version expresses it in terms of complex logarithms. Simple algebraic inputs will automatically simplify to rational multiples of `\pi`. By default, the standard function uses the *logarithm* representation as this typically works best for field arithmetic and simplifications, although it has the disadvantage of introducing complex numbers where real numbers would be sufficient. The behavior of the standard function can be changed using the :macro:`CA_OPT_TRIG_FORM` context setting (exponential mode results in logarithmic forms). For special values, the following definitions apply: * `\operatorname{atan}(\pm i) = \pm i \infty` * `\operatorname{atan}(c \infty) = \operatorname{csgn}(c) \pi / 2` * `\operatorname{atan}(\tilde \infty) = \operatorname{Undefined}` .. function:: void ca_asin_logarithm(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_acos_logarithm(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_asin_direct(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_acos_direct(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_asin(ca_t res, const ca_t x, ca_ctx_t ctx) void ca_acos(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the inverse sine (respectively, cosine) of *x*. The *direct* version expresses the result as an inverse sine or cosine (possibly after transforming the variable). The *logarithm* version expresses it in terms of complex logarithms. Simple algebraic inputs will automatically simplify to rational multiples of `\pi`. By default, the standard function uses the *logarithm* representation as this typically works best for field arithmetic and simplifications, although it has the disadvantage of introducing complex numbers where real numbers would be sufficient. The behavior of the standard function can be changed using the :macro:`CA_OPT_TRIG_FORM` context setting (exponential mode results in logarithmic forms). The inverse cosine is presently implemented as `\operatorname{acos}(x) = \pi/2 - \operatorname{asin}(x)`. Special functions ------------------------------------------------------------------------------- .. function:: void ca_gamma(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the gamma function of *x*. .. function:: void ca_erf(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the error function of *x*. .. function:: void ca_erfc(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the complementary error function of *x*. .. function:: void ca_erfi(ca_t res, const ca_t x, ca_ctx_t ctx) Sets *res* to the imaginary error function of *x*. Numerical evaluation ------------------------------------------------------------------------------- .. function:: void ca_get_acb_raw(acb_t res, const ca_t x, slong prec, ca_ctx_t ctx) Sets *res* to an enclosure of the numerical value of *x*. A working precision of *prec* bits is used internally for the evaluation, without adaptive refinement. If *x* is any special value, *res* is set to *acb_indeterminate*. .. function:: void ca_get_acb(acb_t res, const ca_t x, slong prec, ca_ctx_t ctx) void ca_get_acb_accurate_parts(acb_t res, const ca_t x, slong prec, ca_ctx_t ctx) Sets *res* to an enclosure of the numerical value of *x*. The working precision is increased adaptively to try to ensure *prec* accurate bits in the output. The *accurate_parts* version tries to ensure *prec* accurate bits for both the real and imaginary part separately. The refinement is stopped if the working precision exceeds ``CA_OPT_PREC_LIMIT`` (or twice the initial precision, if this is larger). The user may call *acb_rel_accuracy_bits* to check is the calculation was successful. The output is not rounded down to *prec* bits (to avoid unnecessary double rounding); the user may call *acb_set_round* when rounding is desired. .. function:: char * ca_get_decimal_str(const ca_t x, slong digits, ulong flags, ca_ctx_t ctx) Returns a decimal approximation of *x* with precision up to *digits*. The output is guaranteed to be correct within 1 ulp in the returned digits, but the number of returned digits may be smaller than *digits* if the numerical evaluation does not succeed. If *flags* is set to 1, attempts to achieve full accuracy for both the real and imaginary parts separately. If *x* is not finite or a finite enclosure cannot be produced, returns the string "?". The user should free the returned string with ``flint_free``. Rewriting and simplification ------------------------------------------------------------------------------- .. function:: void ca_rewrite_complex_normal_form(ca_t res, const ca_t x, int deep, ca_ctx_t ctx) Sets *res* to *x* rewritten using standardizing transformations over the complex numbers: * Elementary functions are rewritten in terms of (complex) exponentials, roots and logarithms * Complex parts are rewritten using logarithms, square roots, and (deep) complex conjugates * Algebraic numbers are rewritten in terms of cyclotomic fields where applicable If *deep* is set, the rewriting is applied recursively to the tower of extension numbers; otherwise, the rewriting is only applied to the top-level extension numbers. The result is not a normal form in the strong sense (the same number can have many possible representations even after applying this transformation), but in practice this is a powerful heuristic for simplification. Factorization ------------------------------------------------------------------------------- .. type:: ca_factor_struct .. type:: ca_factor_t Represents a real or complex number in factored form `b_1^{e_1} b_2^{e_2} \cdots b_n^{e_n}` where `b_i` and `e_i` are :type:`ca_t` numbers (the exponents need not be integers). .. function:: void ca_factor_init(ca_factor_t fac, ca_ctx_t ctx) Initializes *fac* and sets it to the empty factorization (equivalent to the number 1). .. function:: void ca_factor_clear(ca_factor_t fac, ca_ctx_t ctx) Clears the factorization structure *fac*. .. function:: void ca_factor_one(ca_factor_t fac, ca_ctx_t ctx) Sets *fac* to the empty factorization (equivalent to the number 1). .. function:: void ca_factor_print(const ca_factor_t fac, ca_ctx_t ctx) Prints a description of *fac* to standard output. .. function:: void ca_factor_insert(ca_factor_t fac, const ca_t base, const ca_t exp, ca_ctx_t ctx) Inserts `b^e` into *fac* where *b* is given by *base* and *e* is given by *exp*. If a base element structurally identical to *base* already exists in *fac*, the corresponding exponent is incremented by *exp*; otherwise, this factor is appended. .. function:: void ca_factor_get_ca(ca_t res, const ca_factor_t fac, ca_ctx_t ctx) Expands *fac* back to a single :type:`ca_t` by evaluating the powers and multiplying out the result. .. function:: void ca_factor(ca_factor_t res, const ca_t x, ulong flags, ca_ctx_t ctx) Sets *res* to a factorization of *x* of the form `x = b_1^{e_1} b_2^{e_2} \cdots b_n^{e_n}`. Requires that *x* is not a special value. The type of factorization is controlled by *flags*, which can be set to a combination of constants in the following section. Factorization options ................................................................................ The following flags select the structural polynomial factorization to perform over formal fields `\mathbb{Q}(a_1,\ldots,a_n)`. Each flag in the list strictly encompasses the factorization power of the preceding flag, so it is unnecessary to pass more than one flag. .. macro:: CA_FACTOR_POLY_NONE No polynomial factorization at all. .. macro:: CA_FACTOR_POLY_CONTENT Only extract the rational content. .. macro:: CA_FACTOR_POLY_SQF Perform a squarefree factorization in addition to extracting the rational content. .. macro:: CA_FACTOR_POLY_FULL Perform a full multivariate polynomial factorization. The following flags select the factorization to perform over `\mathbb{Z}`. Integer factorization is applied if *x* is an element of `\mathbb{Q}`, and to the extracted rational content of polynomials. Each flag in the list strictly encompasses the factorization power of the preceding flag, so it is unnecessary to pass more than one flag. .. macro:: CA_FACTOR_ZZ_NONE No integer factorization at all. .. macro:: CA_FACTOR_ZZ_SMOOTH Perform a smooth factorization to extract small prime factors (heuristically up to ``CA_OPT_SMOOTH_LIMIT`` bits) in addition to identifying perfect powers. .. macro:: CA_FACTOR_ZZ_FULL Perform a complete integer factorization into prime numbers. This is prohibitively slow for general integers exceeding 70-80 digits. .. _context-options: Context options ------------------------------------------------------------------------------- The *options* member of a :type:`ca_ctx_t` object is an array of *slong* values controlling simplification behavior and various other settings. The values of the array at the following indices can be changed by the user (example: ``ctx->options[CA_OPT_PREC_LIMIT] = 65536``). It is recommended to set options controlling evaluation only at the time when a context object is created. Changing such options later should normally be harmless, but since the update will not apply retroactively to objects that have already been computed and cached, one might not see the expected behavior. Superficial options (printing) can be changed at any time. .. macro:: CA_OPT_VERBOSE Whether to print debug information. Default value: 0. .. macro:: CA_OPT_PRINT_FLAGS Printing style. See :ref:`ca-printing` for details. Default value: ``CA_PRINT_DEFAULT``. .. macro:: CA_OPT_MPOLY_ORD Monomial ordering to use for multivariate polynomials. Possible values are ``ORD_LEX``, ``ORD_DEGLEX`` and ``ORD_DEGREVLEX``. Default value: ``ORD_LEX``. This option must be set before doing any computations. .. macro:: CA_OPT_PREC_LIMIT Maximum precision to use internally for numerical evaluation with Arb, and in some cases for the magntiude of exact coefficients. This parameter affects the possibility to prove inequalities and find simplifications between related extension numbers. This is not a strict limit; some calculations may use higher precision when there is a good reason to do so. Default value: 4096. .. macro:: CA_OPT_QQBAR_DEG_LIMIT Maximum degree of :type:`qqbar_t` elements allowed internally during simplification of algebraic numbers. This limit may be exceeded when the user provides explicit :type:`qqbar_t` input of higher degree. Default value: 120. .. macro:: CA_OPT_LOW_PREC Numerical precision to use for fast checks (typically, before attempting more expensive operations). Default value: 64. .. macro:: CA_OPT_SMOOTH_LIMIT Size in bits for factors in smooth integer factorization. Default value: 32. .. macro:: CA_OPT_LLL_PREC Precision to use to find integer relations using LLL. Default value: 128. .. macro:: CA_OPT_POW_LIMIT Largest exponent to expand powers automatically. This only applies in multivariate and transcendental fields: in number fields, ``CA_OPT_PREC_LIMIT`` applies instead. Default value: 20. .. macro:: CA_OPT_USE_GROEBNER Boolean flag for whether to use Gröbner basis computation. This flag and the following limits affect the ability to prove multivariate identities. Default value: 1. .. macro:: CA_OPT_GROEBNER_LENGTH_LIMIT Maximum length of ideal basis allowed in Buchberger's algorithm. Default value: 100. .. macro:: CA_OPT_GROEBNER_POLY_LENGTH_LIMIT Maximum length of polynomials allowed in Buchberger's algorithm. Default value: 1000. .. macro:: CA_OPT_GROEBNER_POLY_BITS_LIMIT Maximum coefficient size in bits of polynomials allowed in Buchberger's algorithm. Default value: 10000. .. macro:: CA_OPT_VIETA_LIMIT Maximum degree *n* of algebraic numbers for which to add Vieta's formulas to the reduction ideal. This must be set relatively low since the number of terms in Vieta's formulas is `O(2^n)` and the resulting Gröbner basis computations can be expensive. Default value: 6. .. macro:: CA_OPT_TRIG_FORM Default representation of trigonometric functions. The following values are possible: .. macro :: CA_TRIG_DIRECT Use the direct functions (with some exceptions). .. macro :: CA_TRIG_EXPONENTIAL Use complex exponentials. .. macro :: CA_TRIG_SINE_COSINE Use sines and cosines. .. macro :: CA_TRIG_TANGENT Use tangents. Default value: ``CA_TRIG_EXPONENTIAL``. The *exponential* representation is currently used by default as typically works best for field arithmetic and simplifications, although it has the disadvantage of introducing complex numbers where real numbers would be sufficient. This may change in the future. Internal representation ------------------------------------------------------------------------------- .. macro:: CA_FMPQ(x) .. macro:: CA_FMPQ_NUMREF(x) .. macro:: CA_FMPQ_DENREF(x) Assuming that *x* holds an element of the trivial field `\mathbb{Q}`, this macro returns a pointer which can be used as an :type:`fmpq_t`, or respectively to the numerator or denominator as an :type:`fmpz_t`. .. macro:: CA_MPOLY_Q(x) Assuming that *x* holds a generic field element as data, this macro returns a pointer which can be used as an :type:`fmpz_mpoly_q_t`. .. macro:: CA_NF_ELEM(x) Assuming that *x* holds an Antic number field element as data, this macro returns a pointer which can be used as an :type:`nf_elem_t`. .. function:: void _ca_make_field_element(ca_t x, slong new_index, ca_ctx_t ctx) Changes the internal representation of *x* to that of an element of the field with index *new_index* in the context object *ctx*. This may destroy the value of *x*. .. function:: void _ca_make_fmpq(ca_t x, ca_ctx_t ctx) Changes the internal representation of *x* to that of an element of the trivial field `\mathbb{Q}`. This may destroy the value of *x*. .. raw:: latex \newpage calcium-0.4.1/doc/source/ca_ext.rst000066400000000000000000000175701407704557200172200ustar00rootroot00000000000000.. _ca-ext: **ca_ext.h** -- real and complex extension numbers =============================================================================== A :type:`ca_ext_t` represents a fixed real or complex number *a*. The content of a :type:`ca_ext_t` can be one of the following: * An algebraic constant represented in canonical form by a :type:`qqbar_t` instance (example: `i`, represented as the root of `x^2+1` with positive imaginary part). * A constant of the form `f(x_1, \ldots, x_n)` where *f* is a builtin symbolic function and `x_1, \ldots, x_n` are given :type:`ca_t` instances. * A builtin symbolic constant such as `\pi`. (This is just a special case of the above with a zero-length argument list.) * (Not implemented): a user-defined constant or function defined by suppling a function pointer for Arb numerical evaluation to specified precision. The :type:`ca_ext_t` structure is heavy-weight object, not just meant to act as a node in a symbolic expression. It will cache various data to support repeated computation with this particular number, including its numerical enclosure and number field data in the case of algebraic numbers. Extension numbers are used internally by the :type:`ca_t` type to define the embeddings `\mathbb{Q}(a) \to \mathbb{C}` of formal fields. The user does not normally need to create :type:`ca_ext_t` instances directly; the intended way for the user to work with the extension number *a* is to create a :type:`ca_t` representing the field element `1 \cdot a`. The underlying :type:`ca_ext_t` may be accessed to determine symbolic and numerical properties of this number. Since extension numbers may depend recursively on nontrivial fields for function arguments, :type:`ca_ext_t` operations require a :type:`ca_ctx_t` context object. Type and macros ------------------------------------------------------------------------------- For all types, a *type_t* is defined as an array of length one of type *type_struct*, permitting a *type_t* to be passed by reference. .. type:: ca_ext_struct .. type:: ca_ext_t An extension number object contains a header, a hash value, data (a :type:`qqbar_t` instance and an Antic :type:`nf_t` in the case of algebraic numbers, and a pointer to arguments in the case of a symbolic function), and a cached :type:`acb_t` enclosure (in the case of a :type:`qqbar_t`, the enclosure internal to that structure is used). .. type:: ca_ext_ptr Alias for ``ca_ext_struct *``. .. type:: ca_ext_srcptr Alias for ``const ca_ext_struct *``. .. macro:: CA_EXT_HEAD(x) Accesses the head (a :type:`calcium_func_code`) of *x*. This is *CA_QQBar* if *x* represents an algebraic constant in canonical form, and *CA_Exp*, *CA_Pi*, etc. for symbolic functions and constants. .. macro:: CA_EXT_HASH(x) Accesses the hash value of *x*. .. macro:: CA_EXT_QQBAR(x) Assuming that *x* represents an algebraic constant in canonical form, accesses this :type:`qqbar_t` object. .. macro:: CA_EXT_QQBAR_NF(x) Assuming that *x* represents an algebraic constant in canonical form, accesses the corresponding Antic number field :type:`nf_t` object. .. macro:: CA_EXT_FUNC_ARGS(x) Assuming that *x* represents a symbolic constant or function, accesses the argument list (as a :type:`ca_ptr`). .. macro:: CA_EXT_FUNC_NARGS(x) Assuming that *x* represents a symbolic constant or function, accesses the number of function arguments. .. macro:: CA_EXT_FUNC_ENCLOSURE(x) Assuming that *x* represents a symbolic constant or function, accesses the cached :type:`acb_t` numerical enclosure. .. macro:: CA_EXT_FUNC_PREC(x) Assuming that *x* represents a symbolic constant or function, accesses the working precision of the cached numerical enclosure. Memory management ------------------------------------------------------------------------------- .. function:: void ca_ext_init_qqbar(ca_ext_t res, const qqbar_t x, ca_ctx_t ctx) Initializes *res* and sets it to the algebraic constant *x*. .. function:: void ca_ext_init_const(ca_ext_t res, calcium_func_code func, ca_ctx_t ctx) Initializes *res* and sets it to the constant defined by *func* (example: *func* = *CA_Pi* for `x = \pi`). .. function:: void ca_ext_init_fx(ca_ext_t res, calcium_func_code func, const ca_t x, ca_ctx_t ctx) Initializes *res* and sets it to the univariate function value `f(x)` where *f* is defined by *func* (example: *func* = *CA_Exp* for `e^x`). .. function:: void ca_ext_init_fxy(ca_ext_t res, calcium_func_code func, const ca_t x, const ca_t y, ca_ctx_t ctx) Initializes *res* and sets it to the bivariate function value `f(x, y)` where *f* is defined by *func* (example: *func* = *CA_Pow* for `x^y`). .. function:: void ca_ext_init_fxn(ca_ext_t res, calcium_func_code func, ca_srcptr x, slong nargs, ca_ctx_t ctx) Initializes *res* and sets it to the multivariate function value `f(x_1, \ldots, x_n)` where *f* is defined by *func* and *n* is given by *nargs*. .. function:: void ca_ext_init_set(ca_ext_t res, const ca_ext_t x, ca_ctx_t ctx) Initializes *res* and sets it to a copy of *x*. .. function:: void ca_ext_clear(ca_ext_t res, ca_ctx_t ctx) Clears *res*. Structure ------------------------------------------------------------------------------- .. function:: slong ca_ext_nargs(const ca_ext_t x, ca_ctx_t ctx) Returns the number of function arguments of *x*. The return value is 0 for any algebraic constant and for any built-in symbolic constant such as `\pi`. .. function:: void ca_ext_get_arg(ca_t res, const ca_ext_t x, slong i, ca_ctx_t ctx) Sets *res* to argument *i* (indexed from zero) of *x*. This calls *flint_abort* if *i* is out of range. .. function:: ulong ca_ext_hash(const ca_ext_t x, ca_ctx_t ctx) Returns a hash of the structural representation of *x*. .. function:: int ca_ext_equal_repr(const ca_ext_t x, const ca_ext_t y, ca_ctx_t ctx) Tests *x* and *y* for structural equality, returning 0 (false) or 1 (true). .. function:: int ca_ext_cmp_repr(const ca_ext_t x, const ca_ext_t y, ca_ctx_t ctx) Compares the representations of *x* and *y* in a canonical sort order, returning -1, 0 or 1. This only performs a structural comparison of the symbolic representations; the return value does not say anything meaningful about the numbers represented by *x* and *y*. Input and output ------------------------------------------------------------------------------- .. function:: void ca_ext_print(const ca_ext_t x, const ca_ctx_t ctx) Prints a description of *x* to standard output. Numerical evaluation ------------------------------------------------------------------------------- .. function:: void ca_ext_get_acb_raw(acb_t res, ca_ext_t x, slong prec, ca_ctx_t ctx) Sets *res* to an enclosure of the numerical value of *x*. A working precision of *prec* bits is used for the evaluation, without adaptive refinement. Cache ------------------------------------------------------------------------------- .. type:: ca_ext_cache_struct .. type:: ca_ext_cache_t Represents a set of structurally distinct :type:`ca_ext_t` instances. This object contains an array of pointers to individual heap-allocated :type:`ca_ext_struct` objects as well as a hash table for quick lookup. .. function:: void ca_ext_cache_init(ca_ext_cache_t cache, ca_ctx_t ctx) Initializes *cache* for use. .. function:: void ca_ext_cache_clear(ca_ext_cache_t cache, ca_ctx_t ctx) Clears *cache*, freeing the memory allocated internally. .. function:: ca_ext_ptr ca_ext_cache_insert(ca_ext_cache_t cache, const ca_ext_t x, ca_ctx_t ctx) Adds *x* to *cache* without duplication. If a structurally identical instance already exists in *cache*, a pointer to that instance is returned. Otherwise, a copy of *x* is inserted into *cache* and a pointer to that new instance is returned. .. raw:: latex \newpage calcium-0.4.1/doc/source/ca_field.rst000066400000000000000000000174251407704557200175020ustar00rootroot00000000000000.. _ca-field: **ca_field.h** -- extension fields =============================================================================== A :type:`ca_field_t` represents the parent field `K = \mathbb{Q}(a_1,\ldots,a_n)` of a :type:`ca_t` element. A :type:`ca_field_t` contains a list of pointers to :type:`ca_ext_t` objects as well as a reduction ideal. The user does not normally need to create :type:`ca_field_t` objects manually: a :type:`ca_ctx_t` context object manages a cache of fields automatically. Internally, three types of field representation are used: * The trivial field `\mathbb{Q}`. * An Antic number field `\mathbb{Q}(a)` where *a* is defined by a :type:`qqbar_t` * A generic field `\mathbb{Q}(a_1,\ldots,a_n)` where `n \ge 1`, and `a_1` is not defined by a :type:`qqbar_t` if `n = 1`. The field type mainly affects the internal storage of the field elements; the distinction is mostly transparent to the external interface. Type and macros ------------------------------------------------------------------------------- For all types, a *type_t* is defined as an array of length one of type *type_struct*, permitting a *type_t* to be passed by reference. .. type:: ca_field_struct .. type:: ca_field_t Represents a formal field. .. type:: ca_field_ptr Alias for ``ca_field_struct *``. .. type:: ca_field_srcptr Alias for ``const ca_field_struct *``. .. macro:: CA_FIELD_LENGTH(K) Accesses the number *n* of extension numbers of *K*. This is 0 if `K = \mathbb{Q}`. .. macro:: CA_FIELD_EXT(K) Accesses the array of extension numbers as a :type:`ca_ext_ptr`. .. macro:: CA_FIELD_EXT_ELEM(K, i) Accesses the extension number at position *i* (indexed from zero) as a :type:`ca_ext_t`. .. macro:: CA_FIELD_HASH(K) Accesses the hash value of *K*. .. macro:: CA_FIELD_IS_QQ(K) Returns whether *K* is the trivial field `\mathbb{Q}`. .. macro:: CA_FIELD_IS_NF(K) Returns whether *K* represents an Antic number field `K = \mathbb{Q}(a)` where *a* is represented by a :type:`qqbar_t`. .. macro:: CA_FIELD_IS_GENERIC(K) Returns whether *K* represents a generic field. .. macro:: CA_FIELD_NF(K) Assuming that *K* represents an Antic number field `K = \mathbb{Q}(a)`, accesses the :type:`nf_t` object representing this field. .. macro:: CA_FIELD_NF_QQBAR(K) Assuming that *K* represents an Antic number field `K = \mathbb{Q}(a)`, accesses the :type:`qqbar_t` object representing *a*. .. macro:: CA_FIELD_IDEAL(K) Assuming that *K* represents a multivariate field, accesses the reduction ideal as a :type:`fmpz_mpoly_t` array. .. macro:: CA_FIELD_IDEAL_ELEM(K, i) Assuming that *K* represents a multivariate field, accesses element *i* (indexed from zero) of the reduction ideal as a :type:`fmpz_mpoly_t`. .. macro:: CA_FIELD_IDEAL_LENGTH(K) Assuming that *K* represents a multivariate field, accesses the number of polynomials in the reduction ideal. .. macro:: CA_FIELD_MCTX(K, ctx) Assuming that *K* represents a multivariate field, accesses the :type:`fmpz_mpoly_ctx_t` context object for multivariate polynomial arithmetic on the internal representation of elements in this field. Memory management ------------------------------------------------------------------------------- .. function:: void ca_field_init_qq(ca_field_t K, ca_ctx_t ctx) Initializes *K* to represent the trivial field `\mathbb{Q}`. .. function:: void ca_field_init_nf(ca_field_t K, const qqbar_t x, ca_ctx_t ctx) Initializes *K* to represent the algebraic number field `\mathbb{Q}(x)`. .. function:: void ca_field_init_const(ca_field_t K, ulong func, ca_ctx_t ctx) Initializes *K* to represent the field `\mathbb{Q}(x)` where *x* is a builtin constant defined by *func* (example: *func* = *CA_Pi* for `x = \pi`). .. function:: void ca_field_init_fx(ca_field_t K, ulong func, const ca_t x, ca_ctx_t ctx) Initializes *K* to represent the field `\mathbb{Q}(a)` where `a = f(x)`, given a number *x* and a builtin univariate function *func* (example: *func* = *CA_Exp* for `e^x`). .. function:: void ca_field_init_fxy(ca_field_t K, calcium_func_code func, const ca_t x, const ca_t y, ca_ctx_t ctx) Initializes *K* to represent the field `\mathbb{Q}(a,b)` where `a = f(x, y)`. .. function:: void ca_field_init_multi(ca_field_t K, slong len, ca_ctx_t ctx) Initializes *K* to represent a multivariate field `\mathbb{Q}(a_1, \ldots, a_n)` in *n* extension numbers. The extension numbers must subsequently be assigned one by one using :func:`ca_field_set_ext`. .. function:: void ca_field_set_ext(ca_field_t K, slong i, slong x_index, ca_ctx_t ctx) Sets the extension number at position *i* (here indexed from 0) of *K* to the generator of the field with index *x_index* in *ctx*. (It is assumed that the generating field is a univariate field.) This only inserts a shallow reference: the field at index *x_index* must be kept alive until *K* has been cleared. .. function:: void ca_field_clear(ca_field_t K, ca_ctx_t ctx) Clears the field *K*. This does not clear the individual extension numbers, which are only held as references. Input and output ------------------------------------------------------------------------------- .. function:: void ca_field_print(const ca_field_t K, const ca_ctx_t ctx) Prints a description of the field *K* to standard output. Ideal ------------------------------------------------------------------------------- .. function:: void ca_field_build_ideal(ca_field_t K, ca_ctx_t ctx) Given *K* with assigned extension numbers, builds the reduction ideal in-place. .. function:: void ca_field_build_ideal_erf(ca_field_t K, ca_ctx_t ctx) Builds relations for error functions present among the extension numbers in *K*. This heuristic adds relations that are consequences of the functional equations `\operatorname{erf}(x) = -\operatorname{erf}(-x)`, `\operatorname{erfc}(x) = 1-\operatorname{erf}(x)`, `\operatorname{erfi}(x) = -i\operatorname{erf}(ix)`. Structure operations ------------------------------------------------------------------------------- .. function:: int ca_field_cmp(const ca_field_t K1, const ca_field_t K2, ca_ctx_t ctx) Compares the field objects *K1* and *K2* in a canonical sort order, returning -1, 0 or 1. This only performs a lexicographic comparison of the representations of *K1* and *K2*; the return value does not say anything meaningful about the relative structures of *K1* and *K2* as mathematical fields. Cache ------------------------------------------------------------------------------- .. type:: ca_field_cache_struct .. type:: ca_field_cache_t Represents a set of distinct :type:`ca_field_t` instances. This object contains an array of pointers to individual heap-allocated :type:`ca_field_struct` objects as well as a hash table for quick lookup. .. function:: void ca_field_cache_init(ca_field_cache_t cache, ca_ctx_t ctx) Initializes *cache* for use. .. function:: void ca_field_cache_clear(ca_field_cache_t cache, ca_ctx_t ctx) Clears *cache*, freeing the memory allocated internally. This does not clear the individual extension numbers, which are only held as references. .. function:: ca_field_ptr ca_field_cache_insert_ext(ca_field_cache_t cache, ca_ext_struct ** x, slong len, ca_ctx_t ctx) Adds the field defined by the length-*len* list of extension numbers *x* to *cache* without duplication. If such a field already exists in *cache*, a pointer to that instance is returned. Otherwise, a field with extension numbers *x* is inserted into *cache* and a pointer to that new instance is returned. Upon insertion of a new field, the reduction ideal is constructed via :func:`ca_field_build_ideal`. .. raw:: latex \newpage calcium-0.4.1/doc/source/ca_mat.rst000066400000000000000000000702751407704557200172020ustar00rootroot00000000000000.. _ca-mat: **ca_mat.h** -- matrices over the real and complex numbers =============================================================================== A :type:`ca_mat_t` represents a dense matrix over the real or complex numbers, implemented as an array of entries of type :type:`ca_struct`. The dimension (number of rows and columns) of a matrix is fixed at initialization, and the user must ensure that inputs and outputs to an operation have compatible dimensions. The number of rows or columns in a matrix can be zero. Types, macros and constants ------------------------------------------------------------------------------- .. type:: ca_mat_struct .. type:: ca_mat_t Contains a pointer to a flat array of the entries (*entries*), an array of pointers to the start of each row (*rows*), and the number of rows (*r*) and columns (*c*). A *ca_mat_t* is defined as an array of length one of type *ca_mat_struct*, permitting a *ca_mat_t* to be passed by reference. .. macro:: ca_mat_entry(mat, i, j) Macro giving a pointer to the entry at row *i* and column *j*. .. macro:: ca_mat_nrows(mat) Returns the number of rows of the matrix. .. macro:: ca_mat_ncols(mat) Returns the number of columns of the matrix. .. function:: ca_ptr ca_mat_entry_ptr(ca_mat_t mat, slong i, slong j) Returns a pointer to the entry at row *i* and column *j*. Equivalent to :macro:`ca_mat_entry` but implemented as a function. Memory management ------------------------------------------------------------------------------- .. function:: void ca_mat_init(ca_mat_t mat, slong r, slong c, ca_ctx_t ctx) Initializes the matrix, setting it to the zero matrix with *r* rows and *c* columns. .. function:: void ca_mat_clear(ca_mat_t mat, ca_ctx_t ctx) Clears the matrix, deallocating all entries. .. function:: void ca_mat_swap(ca_mat_t mat1, ca_mat_t mat2, ca_ctx_t ctx) Efficiently swaps *mat1* and *mat2*. .. function:: void ca_mat_window_init(ca_mat_t window, const ca_mat_t mat, slong r1, slong c1, slong r2, slong c2, ca_ctx_t ctx) Initializes *window* to a window matrix into the submatrix of *mat* starting at the corner at row *r1* and column *c1* (inclusive) and ending at row *r2* and column *c2* (exclusive). .. function:: void ca_mat_window_clear(ca_mat_t window, ca_ctx_t ctx) Frees the window matrix. Assignment and conversions ------------------------------------------------------------------------------- .. function:: void ca_mat_set(ca_mat_t dest, const ca_mat_t src, ca_ctx_t ctx) void ca_mat_set_fmpz_mat(ca_mat_t dest, const fmpz_mat_t src, ca_ctx_t ctx) void ca_mat_set_fmpq_mat(ca_mat_t dest, const fmpq_mat_t src, ca_ctx_t ctx) Sets *dest* to *src*. The operands must have identical dimensions. .. function:: void ca_mat_set_ca(ca_mat_t mat, const ca_t c, ca_ctx_t ctx) Sets *mat* to the matrix with the scalar *c* on the main diagonal and zeros elsewhere. .. function:: void ca_mat_transfer(ca_mat_t res, ca_ctx_t res_ctx, const ca_mat_t src, ca_ctx_t src_ctx) Sets *res* to *src* where the corresponding context objects *res_ctx* and *src_ctx* may be different. This operation preserves the mathematical value represented by *src*, but may result in a different internal representation depending on the settings of the context objects. Random generation ------------------------------------------------------------------------------- .. function:: void ca_mat_randtest(ca_mat_t mat, flint_rand_t state, slong depth, slong bits, ca_ctx_t ctx) Sets *mat* to a random matrix with entries having complexity up to *depth* and *bits* (see :func:`ca_randtest`). .. function:: void ca_mat_randtest_rational(ca_mat_t mat, flint_rand_t state, slong bits, ca_ctx_t ctx) Sets *mat* to a random rational matrix with entries up to *bits* bits in size. .. function:: void ca_mat_randops(ca_mat_t mat, flint_rand_t state, slong count, ca_ctx_t ctx) Randomizes *mat* in-place by performing elementary row or column operations. More precisely, at most count random additions or subtractions of distinct rows and columns will be performed. This leaves the rank (and for square matrices, the determinant) unchanged. Input and output ------------------------------------------------------------------------------- .. function:: void ca_mat_print(const ca_mat_t mat, ca_ctx_t ctx) Prints *mat* to standard output. The entries are printed on separate lines. .. function:: void ca_mat_printn(const ca_mat_t mat, slong digits, ca_ctx_t ctx) Prints a decimal representation of *mat* with precision specified by *digits*. The entries are comma-separated with square brackets and comma separation for the rows. Special matrices ------------------------------------------------------------------------------- .. function:: void ca_mat_zero(ca_mat_t mat, ca_ctx_t ctx) Sets all entries in *mat* to zero. .. function:: void ca_mat_one(ca_mat_t mat, ca_ctx_t ctx) Sets the entries on the main diagonal of *mat* to one, and all other entries to zero. .. function:: void ca_mat_ones(ca_mat_t mat, ca_ctx_t ctx) Sets all entries in *mat* to one. .. function:: void ca_mat_pascal(ca_mat_t mat, int triangular, ca_ctx_t ctx) Sets *mat* to a Pascal matrix, whose entries are binomial coefficients. If *triangular* is 0, constructs a full symmetric matrix with the rows of Pascal's triangle as successive antidiagonals. If *triangular* is 1, constructs the upper triangular matrix with the rows of Pascal's triangle as columns, and if *triangular* is -1, constructs the lower triangular matrix with the rows of Pascal's triangle as rows. .. function:: void ca_mat_stirling(ca_mat_t mat, int kind, ca_ctx_t ctx) Sets *mat* to a Stirling matrix, whose entries are Stirling numbers. If *kind* is 0, the entries are set to the unsigned Stirling numbers of the first kind. If *kind* is 1, the entries are set to the signed Stirling numbers of the first kind. If *kind* is 2, the entries are set to the Stirling numbers of the second kind. .. function:: void ca_mat_hilbert(ca_mat_t mat, ca_ctx_t ctx) Sets *mat* to the Hilbert matrix, which has entries `A_{i,j} = 1/(i+j+1)`. .. function:: void ca_mat_dft(ca_mat_t mat, int type, ca_ctx_t ctx) Sets *mat* to the DFT (discrete Fourier transform) matrix of order *n* where *n* is the smallest dimension of *mat* (if *mat* is not square, the matrix is extended periodically along the larger dimension). The *type* parameter selects between four different versions of the DFT matrix (in which `\omega = e^{2\pi i/n}`): * Type 0 -- entries `A_{j,k} = \omega^{-jk}` * Type 1 -- entries `A_{j,k} = \omega^{jk} / n` * Type 2 -- entries `A_{j,k} = \omega^{-jk} / \sqrt{n}` * Type 3 -- entries `A_{j,k} = \omega^{jk} / \sqrt{n}` The type 0 and 1 matrices are inverse pairs, and similarly for the type 2 and 3 matrices. Comparisons and properties ------------------------------------------------------------------------------- .. function:: truth_t ca_mat_check_equal(const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) Compares *A* and *B* for equality. .. function:: truth_t ca_mat_check_is_zero(const ca_mat_t A, ca_ctx_t ctx) Tests if *A* is the zero matrix. .. function:: truth_t ca_mat_check_is_one(const ca_mat_t A, ca_ctx_t ctx) Tests if *A* has ones on the main diagonal and zeros elsewhere. Conjugate and transpose ------------------------------------------------------------------------------- .. function:: void ca_mat_transpose(ca_mat_t res, const ca_mat_t A, ca_ctx_t ctx) Sets *res* to the transpose of *A*. .. function:: void ca_mat_conj(ca_mat_t res, const ca_mat_t A, ca_ctx_t ctx) Sets *res* to the entrywise complex conjugate of *A*. .. function:: void ca_mat_conj_transpose(ca_mat_t res, const ca_mat_t A, ca_ctx_t ctx) Sets *res* to the conjugate transpose (Hermitian transpose) of *A*. Arithmetic ------------------------------------------------------------------------------- .. function:: void ca_mat_neg(ca_mat_t res, const ca_mat_t A, ca_ctx_t ctx) Sets *res* to the negation of *A*. .. function:: void ca_mat_add(ca_mat_t res, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) Sets *res* to the sum of *A* and *B*. .. function:: void ca_mat_sub(ca_mat_t res, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) Sets *res* to the difference of *A* and *B*. .. function:: void ca_mat_mul_classical(ca_mat_t res, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) void ca_mat_mul_same_nf(ca_mat_t res, const ca_mat_t A, const ca_mat_t B, ca_field_t K, ca_ctx_t ctx) void ca_mat_mul(ca_mat_t res, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) Sets *res* to the matrix product of *A* and *B*. The *classical* version uses classical multiplication. The *same_nf* version assumes (not checked) that both *A* and *B* have coefficients in the same simple algebraic number field *K* or in `\mathbb{Q}`. The default version chooses an algorithm automatically. .. function:: void ca_mat_mul_si(ca_mat_t B, const ca_mat_t A, slong c, ca_ctx_t ctx) void ca_mat_mul_fmpz(ca_mat_t B, const ca_mat_t A, const fmpz_t c, ca_ctx_t ctx) void ca_mat_mul_fmpq(ca_mat_t B, const ca_mat_t A, const fmpq_t c, ca_ctx_t ctx) void ca_mat_mul_ca(ca_mat_t B, const ca_mat_t A, const ca_t c, ca_ctx_t ctx) Sets *B* to *A* multiplied by the scalar *c*. .. function:: void ca_mat_div_si(ca_mat_t B, const ca_mat_t A, slong c, ca_ctx_t ctx) void ca_mat_div_fmpz(ca_mat_t B, const ca_mat_t A, const fmpz_t c, ca_ctx_t ctx) void ca_mat_div_fmpq(ca_mat_t B, const ca_mat_t A, const fmpq_t c, ca_ctx_t ctx) void ca_mat_div_ca(ca_mat_t B, const ca_mat_t A, const ca_t c, ca_ctx_t ctx) Sets *B* to *A* divided by the scalar *c*. .. function:: void ca_mat_add_ca(ca_mat_t B, const ca_mat_t A, const ca_t c, ca_ctx_t ctx) void ca_mat_sub_ca(ca_mat_t B, const ca_mat_t A, const ca_t c, ca_ctx_t ctx) Sets *B* to *A* plus or minus the scalar *c* (interpreted as a diagonal matrix). .. function:: void ca_mat_addmul_ca(ca_mat_t B, const ca_mat_t A, const ca_t c, ca_ctx_t ctx) void ca_mat_submul_ca(ca_mat_t B, const ca_mat_t A, const ca_t c, ca_ctx_t ctx) Sets the matrix *B* to *B* plus (or minus) the matrix *A* multiplied by the scalar *c*. Powers ------------------------------------------------------------------------------- .. function:: void ca_mat_sqr(ca_mat_t B, const ca_mat_t A, ca_ctx_t ctx) Sets *B* to the square of *A*. .. function:: void ca_mat_pow_ui_binexp(ca_mat_t B, const ca_mat_t A, ulong exp, ca_ctx_t ctx) Sets *B* to *A* raised to the power *exp*, evaluated using binary exponentiation. Polynomial evaluation ------------------------------------------------------------------------------- .. function:: void _ca_mat_ca_poly_evaluate(ca_mat_t res, ca_srcptr poly, slong len, const ca_mat_t A, ca_ctx_t ctx) void ca_mat_ca_poly_evaluate(ca_mat_t res, const ca_poly_t poly, const ca_mat_t A, ca_ctx_t ctx) Sets *res* to `f(A)` where *f* is the polynomial given by *poly* and *A* is a square matrix. Uses the Paterson-Stockmeyer algorithm. Gaussian elimination and LU decomposition ------------------------------------------------------------------------------- .. function:: truth_t ca_mat_find_pivot(slong * pivot_row, ca_mat_t mat, slong start_row, slong end_row, slong column, ca_ctx_t ctx) Attempts to find a nonzero entry in *mat* with column index *column* and row index between *start_row* (inclusive) and *end_row* (exclusive). If the return value is ``T_TRUE``, such an element exists, and *pivot_row* is set to the row index. If the return value is ``T_FALSE``, no such element exists (all entries in this part of the column are zero). If the return value is ``T_UNKNOWN``, it is unknown whether such an element exists (zero certification failed). This function is destructive: any elements that are nontrivially zero but can be certified zero will be overwritten by exact zeros. .. function:: int ca_mat_lu_classical(slong * rank, slong * P, ca_mat_t LU, const ca_mat_t A, int rank_check, ca_ctx_t ctx) int ca_mat_lu_recursive(slong * rank, slong * P, ca_mat_t LU, const ca_mat_t A, int rank_check, ca_ctx_t ctx) int ca_mat_lu(slong * rank, slong * P, ca_mat_t LU, const ca_mat_t A, int rank_check, ca_ctx_t ctx) Computes a generalized LU decomposition `A = PLU` of a given matrix *A*, writing the rank of *A* to *rank*. If *A* is a nonsingular square matrix, *LU* will be set to a unit diagonal lower triangular matrix *L* and an upper triangular matrix *U* (the diagonal of *L* will not be stored explicitly). If *A* is an arbitrary matrix of rank *r*, *U* will be in row echelon form having *r* nonzero rows, and *L* will be lower triangular but truncated to *r* columns, having implicit ones on the *r* first entries of the main diagonal. All other entries will be zero. If a nonzero value for ``rank_check`` is passed, the function will abandon the output matrix in an undefined state and set the rank to 0 if *A* is detected to be rank-deficient. The algorithm can fail if it fails to certify that a pivot element is zero or nonzero, in which case the correct rank cannot be determined. The return value is 1 on success and 0 on failure. On failure, the data in the output variables ``rank``, ``P`` and ``LU`` will be meaningless. The *classical* version uses iterative Gaussian elimination. The *recursive* version uses a block recursive algorithm to take advantage of fast matrix multiplication. .. function:: int ca_mat_fflu(slong * rank, slong * P, ca_mat_t LU, ca_t den, const ca_mat_t A, int rank_check, ca_ctx_t ctx) Similar to :func:`ca_mat_lu`, but computes a fraction-free LU decomposition using the Bareiss algorithm. The denominator is written to *den*. Note that despite being "fraction-free", this algorithm may introduce fractions due to incomplete symbolic simplifications. .. function:: truth_t ca_mat_nonsingular_lu(slong * P, ca_mat_t LU, const ca_mat_t A, ca_ctx_t ctx) Wrapper for :func:`ca_mat_lu`. If *A* can be proved to be invertible/nonsingular, returns ``T_TRUE`` and sets *P* and *LU* to a LU decomposition `A = PLU`. If *A* can be proved to be singular, returns ``T_FALSE``. If *A* cannot be proved to be either singular or nonsingular, returns ``T_UNKNOWN``. When the return value is ``T_FALSE`` or ``T_UNKNOWN``, the LU factorization is not completed and the values of *P* and *LU* are arbitrary. .. function:: truth_t ca_mat_nonsingular_fflu(slong * P, ca_mat_t LU, ca_t den, const ca_mat_t A, ca_ctx_t ctx) Wrapper for :func:`ca_mat_fflu`. Similar to :func:`ca_mat_nonsingular_lu`, but computes a fraction-free LU decomposition using the Bareiss algorithm. The denominator is written to *den*. Note that despite being "fraction-free", this algorithm may introduce fractions due to incomplete symbolic simplifications. Solving and inverse ------------------------------------------------------------------------------- .. function:: truth_t ca_mat_inv(ca_mat_t X, const ca_mat_t A, ca_ctx_t ctx) Determines if the square matrix *A* is nonsingular, and if successful, sets `X = A^{-1}` and returns ``T_TRUE``. Returns ``T_FALSE`` if *A* is singular, and ``T_UNKNOWN`` if the rank of *A* cannot be determined. .. function:: truth_t ca_mat_nonsingular_solve_adjugate(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) truth_t ca_mat_nonsingular_solve_fflu(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) truth_t ca_mat_nonsingular_solve_lu(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) truth_t ca_mat_nonsingular_solve(ca_mat_t X, const ca_mat_t A, const ca_mat_t B, ca_ctx_t ctx) Determines if the square matrix *A* is nonsingular, and if successful, solves `AX = B` and returns ``T_TRUE``. Returns ``T_FALSE`` if *A* is singular, and ``T_UNKNOWN`` if the rank of *A* cannot be determined. .. function:: void ca_mat_solve_tril_classical(ca_mat_t X, const ca_mat_t L, const ca_mat_t B, int unit, ca_ctx_t ctx) void ca_mat_solve_tril_recursive(ca_mat_t X, const ca_mat_t L, const ca_mat_t B, int unit, ca_ctx_t ctx) void ca_mat_solve_tril(ca_mat_t X, const ca_mat_t L, const ca_mat_t B, int unit, ca_ctx_t ctx) void ca_mat_solve_triu_classical(ca_mat_t X, const ca_mat_t U, const ca_mat_t B, int unit, ca_ctx_t ctx) void ca_mat_solve_triu_recursive(ca_mat_t X, const ca_mat_t U, const ca_mat_t B, int unit, ca_ctx_t ctx) void ca_mat_solve_triu(ca_mat_t X, const ca_mat_t U, const ca_mat_t B, int unit, ca_ctx_t ctx) Solves the lower triangular system `LX = B` or the upper triangular system `UX = B`, respectively. It is assumed (not checked) that the diagonal entries are nonzero. If *unit* is set, the main diagonal of *L* or *U* is taken to consist of all ones, and in that case the actual entries on the diagonal are not read at all and can contain other data. The *classical* versions perform the computations iteratively while the *recursive* versions perform the computations in a block recursive way to benefit from fast matrix multiplication. The default versions choose an algorithm automatically. .. function:: void ca_mat_solve_fflu_precomp(ca_mat_t X, const slong * perm, const ca_mat_t A, const ca_t den, const ca_mat_t B, ca_ctx_t ctx) void ca_mat_solve_lu_precomp(ca_mat_t X, const slong * P, const ca_mat_t LU, const ca_mat_t B, ca_ctx_t ctx) Solves `AX = B` given the precomputed nonsingular LU decomposition `A = PLU` or fraction-free LU decomposition with denominator *den*. The matrices `X` and `B` are allowed to be aliased with each other, but `X` is not allowed to be aliased with `LU`. Rank and echelon form ------------------------------------------------------------------------------- .. function:: int ca_mat_rank(slong * rank, const ca_mat_t A, ca_ctx_t ctx) Computes the rank of the matrix *A*. If successful, returns 1 and writes the rank to ``rank``. If unsuccessful, returns 0. .. function:: int ca_mat_rref_fflu(slong * rank, ca_mat_t R, const ca_mat_t A, ca_ctx_t ctx) int ca_mat_rref_lu(slong * rank, ca_mat_t R, const ca_mat_t A, ca_ctx_t ctx) int ca_mat_rref(slong * rank, ca_mat_t R, const ca_mat_t A, ca_ctx_t ctx) Computes the reduced row echelon form (rref) of a given matrix. On success, sets *R* to the rref of *A*, writes the rank to *rank*, and returns 1. On failure to certify the correct rank, returns 0, leaving the data in *rank* and *R* meaningless. The *fflu* version computes a fraction-free LU decomposition and then converts the output ro rref form. The *lu* version computes a regular LU decomposition and then converts the output to rref form. The default version uses an automatic algorithm choice and may implement additional methods for special cases. .. function:: int ca_mat_right_kernel(ca_mat_t X, const ca_mat_t A, ca_ctx_t ctx) Sets *X* to a basis of the right kernel (nullspace) of *A*. The output matrix *X* will be resized in-place to have a number of columns equal to the nullity of *A*. Returns 1 on success. On failure, returns 0 and leaves the data in *X* meaningless. Determinant and trace ------------------------------------------------------------------------------- .. function:: void ca_mat_trace(ca_t trace, const ca_mat_t mat, ca_ctx_t ctx) Sets *trace* to the sum of the entries on the main diagonal of *mat*. .. function:: void ca_mat_det_berkowitz(ca_t det, const ca_mat_t A, ca_ctx_t ctx) int ca_mat_det_lu(ca_t det, const ca_mat_t A, ca_ctx_t ctx) int ca_mat_det_bareiss(ca_t det, const ca_mat_t A, ca_ctx_t ctx) void ca_mat_det_cofactor(ca_t det, const ca_mat_t A, ca_ctx_t ctx) void ca_mat_det(ca_t det, const ca_mat_t A, ca_ctx_t ctx) Sets *det* to the determinant of the square matrix *A*. Various algorithms are available: * The *berkowitz* version uses the division-free Berkowitz algorithm performing `O(n^4)` operations. Since no zero tests are required, it is guaranteed to succeed. * The *cofactor* version performs cofactor expansion. This is currently only supported for matrices up to size 4. * The *lu* and *bareiss* versions use rational LU decomposition and fraction-free LU decomposition (Bareiss algorithm) respectively, requiring `O(n^3)` operations. These algorithms can fail if zero certification fails (see :func:`ca_mat_nonsingular_lu`); they return 1 for success and 0 for failure. Note that the Bareiss algorithm, despite being "fraction-free", may introduce fractions due to incomplete symbolic simplifications. The default function chooses an algorithm automatically. It will, in addition, recognize trivially rational and integer matrices and evaluate those determinants using :type:`fmpq_mat_t` or :type:`fmpz_mat_t`. The various algorithms can produce different symbolic forms of the same determinant. Which algorithm performs better depends strongly and sometimes unpredictably on the structure of the matrix. .. function:: void ca_mat_adjugate_cofactor(ca_mat_t adj, ca_t det, const ca_mat_t A, ca_ctx_t ctx) void ca_mat_adjugate_charpoly(ca_mat_t adj, ca_t det, const ca_mat_t A, ca_ctx_t ctx) void ca_mat_adjugate(ca_mat_t adj, ca_t det, const ca_mat_t A, ca_ctx_t ctx) Sets *adj* to the adjuate matrix of *A* and *det* to the determinant of *A*, both computed simultaneously. The *cofactor* version uses cofactor expansion. The *charpoly* version computes and evaluates the characteristic polynomial. The default version uses an automatic algorithm choice. Characteristic polynomial ------------------------------------------------------------------------------- .. function:: void _ca_mat_charpoly_berkowitz(ca_ptr cp, const ca_mat_t mat, ca_ctx_t ctx) void ca_mat_charpoly_berkowitz(ca_poly_t cp, const ca_mat_t mat, ca_ctx_t ctx) int _ca_mat_charpoly_danilevsky(ca_ptr cp, const ca_mat_t mat, ca_ctx_t ctx) int ca_mat_charpoly_danilevsky(ca_poly_t cp, const ca_mat_t mat, ca_ctx_t ctx) void _ca_mat_charpoly(ca_ptr cp, const ca_mat_t mat, ca_ctx_t ctx) void ca_mat_charpoly(ca_poly_t cp, const ca_mat_t mat, ca_ctx_t ctx) Sets *poly* to the characteristic polynomial of *mat* which must be a square matrix. If the matrix has *n* rows, the underscore method requires space for `n + 1` output coefficients. The *berkowitz* version uses a division-free algorithm requiring `O(n^4)` operations. The *danilevsky* version only performs `O(n^3)` operations, but performs divisions and needs to check for zero which can fail. This version returns 1 on success and 0 on failure. The default version chooses an algorithm automatically. .. function:: int ca_mat_companion(ca_mat_t mat, const ca_poly_t poly, ca_ctx_t ctx) Sets *mat* to the companion matrix of *poly*. This function verifies that the leading coefficient of *poly* is provably nonzero and that the output matrix has the right size, returning 1 on success. It returns 0 if the leading coefficient of *poly* cannot be proved nonzero or if the size of the output matrix does not match. Eigenvalues and eigenvectors ------------------------------------------------------------------------------- .. function:: int ca_mat_eigenvalues(ca_vec_t lambda, ulong * exp, const ca_mat_t mat, ca_ctx_t ctx) Attempts to compute all complex eigenvalues of the given matrix *mat*. On success, returns 1 and sets *lambda* to the distinct eigenvalues with corresponding multiplicities in *exp*. The eigenvalues are returned in arbitrary order. On failure, returns 0 and leaves the values in *lambda* and *exp* arbitrary. This function effectively computes the characteristic polynomial and then calls :type:`ca_poly_roots`. .. function:: truth_t ca_mat_diagonalization(ca_mat_t D, ca_mat_t P, const ca_mat_t A, ca_ctx_t ctx) Matrix diagonalization: attempts to compute a diagonal matrix *D* and an invertible matrix *P* such that `A = PDP^{-1}`. Returns ``T_TRUE`` if *A* is diagonalizable and the computation succeeds, ``T_FALSE`` if *A* is provably not diagonalizable, and ``T_UNKNOWN`` if it is unknown whether *A* is diagonalizable. If the return value is not ``T_TRUE``, the values in *D* and *P* are arbitrary. Jordan canonical form ------------------------------------------------------------------------------- .. function:: int ca_mat_jordan_blocks(ca_vec_t lambda, slong * num_blocks, slong * block_lambda, slong * block_size, const ca_mat_t A, ca_ctx_t ctx) Computes the blocks of the Jordan canonical form of *A*. On success, returns 1 and sets *lambda* to the unique eigenvalues of *A*, sets *num_blocks* to the number of Jordan blocks, entry *i* of *block_lambda* to the index of the eigenvalue in Jordan block *i*, and entry *i* of *block_size* to the size of Jordan block *i*. On failure, returns 0, leaving arbitrary values in the output variables. The user should allocate space in *block_lambda* and *block_size* for up to *n* entries where *n* is the size of the matrix. The Jordan form is unique up to the ordering of blocks, which is arbitrary. .. function:: void ca_mat_set_jordan_blocks(ca_mat_t mat, const ca_vec_t lambda, slong num_blocks, slong * block_lambda, slong * block_size, ca_ctx_t ctx) Sets *mat* to the concatenation of the Jordan blocks given in *lambda*, *num_blocks*, *block_lambda* and *block_size*. See :func:`ca_mat_jordan_blocks` for an explanation of these variables. .. function:: int ca_mat_jordan_transformation(ca_mat_t mat, const ca_vec_t lambda, slong num_blocks, slong * block_lambda, slong * block_size, const ca_mat_t A, ca_ctx_t ctx) Given the precomputed Jordan block decomposition (*lambda*, *num_blocks*, *block_lambda*, *block_size*) of the square matrix *A*, computes the corresponding transformation matrix *P* such that `A = P J P^{-1}`. On success, writes *P* to *mat* and returns 1. On failure, returns 0, leaving the value of *mat* arbitrary. .. function:: int ca_mat_jordan_form(ca_mat_t J, ca_mat_t P, const ca_mat_t A, ca_ctx_t ctx) Computes the Jordan decomposition `A = P J P^{-1}` of the given square matrix *A*. The user can pass *NULL* for the output variable *P*, in which case only *J* is computed. On success, returns 1. On failure, returns 0, leaving the values of *J* and *P* arbitrary. This function is a convenience wrapper around :func:`ca_mat_jordan_blocks`, :func:`ca_mat_set_jordan_blocks` and :func:`ca_mat_jordan_transformation`. For computations with the Jordan decomposition, it is often better to use those methods directly since they give direct access to the spectrum and block structure. Matrix functions ------------------------------------------------------------------------------- .. function:: int ca_mat_exp(ca_mat_t res, const ca_mat_t A, ca_ctx_t ctx) Matrix exponential: given a square matrix *A*, sets *res* to `e^A` and returns 1 on success. If unsuccessful, returns 0, leaving the values in *res* arbitrary. This function uses Jordan decomposition. The matrix exponential always exists, but computation can fail if computing the Jordan decomposition fails. .. function:: truth_t ca_mat_log(ca_mat_t res, const ca_mat_t A, ca_ctx_t ctx) Matrix logarithm: given a square matrix *A*, sets *res* to a logarithm `\log(A)` and returns ``T_TRUE`` on success. If *A* can be proved to have no logarithm, returns ``T_FALSE``. If the existence of a logarithm cannot be proved, returns ``T_UNKNOWN``. This function uses the Jordan decomposition, and the branch of the matrix logarithm is defined by taking the principal values of the logarithms of all eigenvalues. calcium-0.4.1/doc/source/ca_poly.rst000066400000000000000000000476161407704557200174070ustar00rootroot00000000000000.. _ca-poly: **ca_poly.h** -- dense univariate polynomials over the real and complex numbers =============================================================================== A :type:`ca_poly_t` represents a univariate polynomial over the real or complex numbers (an element of `\mathbb{R}[X]` or `\mathbb{C}[X]`), implemented as an array of coefficients of type :type:`ca_struct`. Most functions are provided in two versions: an underscore method which operates directly on pre-allocated arrays of coefficients and generally has some restrictions (such as requiring the lengths to be nonzero and not supporting aliasing of the input and output arrays), and a non-underscore method which performs automatic memory management and handles degenerate cases. Warnings: * A polynomial is always normalised by removing zero coefficients at the top. Coefficients will not be removed when Calcium is unable to prove that they are zero. The represented degree can therefore be larger than the degree of the mathematical polynomial. When the correct degree is needed, it is important to verify the leading coefficient. (Of course, this will never be an issue with polynomials that are explicitly monic, for example.) * The special values *Undefined*, unsigned infinity and signed infinity supported by the scalar :type:`ca_t` type are not really meaningful as coefficients of polynomials. We normally assume that the user does not assign those values to coefficients of polynomials, and the functions in this module will likewise normally not generate such coefficients. *Unknown* can still appear as a coefficient representing a number that is inaccessible for computation. A polynomial with numerical coefficients and with a nonzero leading coefficient is called *proper*. The function :func:`ca_poly_is_proper` can be used to check for violations. Types, macros and constants ------------------------------------------------------------------------------- .. type:: ca_poly_struct .. type:: ca_poly_t Contains a pointer to an array of coefficients (*coeffs*), the used length (*length*), and the allocated size of the array (*alloc*). A *ca_poly_t* is defined as an array of length one of type *ca_poly_struct*, permitting an *ca_poly_t* to be passed by reference. Memory management ------------------------------------------------------------------------------- .. function:: void ca_poly_init(ca_poly_t poly, ca_ctx_t ctx) Initializes the polynomial for use, setting it to the zero polynomial. .. function:: void ca_poly_clear(ca_poly_t poly, ca_ctx_t ctx) Clears the polynomial, deallocating all coefficients and the coefficient array. .. function:: void ca_poly_fit_length(ca_poly_t poly, slong len, ca_ctx_t ctx) Makes sure that the coefficient array of the polynomial contains at least *len* initialized coefficients. .. function:: void _ca_poly_set_length(ca_poly_t poly, slong len, ca_ctx_t ctx) Directly changes the length of the polynomial, without allocating or deallocating coefficients. The value should not exceed the allocation length. .. function:: void _ca_poly_normalise(ca_poly_t poly, ca_ctx_t ctx) Strips any top coefficients which can be proved identical to zero. Assignment and simple values ------------------------------------------------------------------------------- .. function:: void ca_poly_zero(ca_poly_t poly, ca_ctx_t ctx) Sets *poly* to the zero polynomial. .. function:: void ca_poly_one(ca_poly_t poly, ca_ctx_t ctx) Sets *poly* to the constant polynomial 1. .. function:: void ca_poly_x(ca_poly_t poly, ca_ctx_t ctx) Sets *poly* to the monomial *x*. .. function:: void ca_poly_set_ca(ca_poly_t poly, const ca_t c, ca_ctx_t ctx) void ca_poly_set_si(ca_poly_t poly, slong c, ca_ctx_t ctx) Sets *poly* to the constant polynomial *c*. .. function:: void ca_poly_set(ca_poly_t res, const ca_poly_t src, ca_ctx_t ctx) void ca_poly_set_fmpz_poly(ca_poly_t res, const fmpz_poly_t src, ca_ctx_t ctx) void ca_poly_set_fmpq_poly(ca_poly_t res, const fmpq_poly_t src, ca_ctx_t ctx) Sets *poly* the polynomial *src*. .. function:: void ca_poly_set_coeff_ca(ca_poly_t poly, slong n, const ca_t x, ca_ctx_t ctx) Sets the coefficient at position *n* in *poly* to *x*. .. function:: void ca_poly_transfer(ca_poly_t res, ca_ctx_t res_ctx, const ca_poly_t src, ca_ctx_t src_ctx) Sets *res* to *src* where the corresponding context objects *res_ctx* and *src_ctx* may be different. This operation preserves the mathematical value represented by *src*, but may result in a different internal representation depending on the settings of the context objects. Random generation ------------------------------------------------------------------------------- .. function:: void ca_poly_randtest(ca_poly_t poly, flint_rand_t state, slong len, slong depth, slong bits, ca_ctx_t ctx) Sets *poly* to a random polynomial of length up to *len* and with entries having complexity up to *depth* and *bits* (see :func:`ca_randtest`). .. function:: void ca_poly_randtest_rational(ca_poly_t poly, flint_rand_t state, slong len, slong bits, ca_ctx_t ctx) Sets *poly* to a random rational polynomial of length up to *len* and with entries up to *bits* bits in size. Input and output ------------------------------------------------------------------------------- .. function:: void ca_poly_print(const ca_poly_t poly, ca_ctx_t ctx) Prints *poly* to standard output. The coefficients are printed on separate lines. .. function:: void ca_poly_printn(const ca_poly_t poly, slong digits, ca_ctx_t ctx) Prints a decimal representation of *poly* with precision specified by *digits*. The coefficients are comma-separated and the whole list is enclosed in square brackets. Degree and leading coefficient ------------------------------------------------------------------------------- .. function:: int ca_poly_is_proper(const ca_poly_t poly, ca_ctx_t ctx) Checks that *poly* represents an element of `\mathbb{C}[X]` with well-defined degree. This returns 1 if the leading coefficient of *poly* is nonzero and all coefficients of *poly* are numbers (not special values). It returns 0 otherwise. It returns 1 when *poly* is precisely the zero polynomial (which does not have a leading coefficient). .. function:: int ca_poly_make_monic(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx) Makes *poly* monic by dividing by the leading coefficient if possible and returns 1. Returns 0 if the leading coefficient cannot be certified to be nonzero, or if *poly* is the zero polynomial. .. function:: void _ca_poly_reverse(ca_ptr res, ca_srcptr poly, slong len, slong n, ca_ctx_t ctx) .. function:: void ca_poly_reverse(ca_poly_t res, const ca_poly_t poly, slong n, ca_ctx_t ctx) Sets *res* to the reversal of *poly* considered as a polynomial of length *n*, zero-padding if needed. The underscore method assumes that *len* is positive and less than or equal to *n*. Comparisons ------------------------------------------------------------------------------- .. function:: truth_t _ca_poly_check_equal(ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) truth_t ca_poly_check_equal(const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) Checks if *poly1* and *poly2* represent the same polynomial. The underscore method assumes that *len1* is at least as large as *len2*. .. function:: truth_t ca_poly_check_is_zero(const ca_poly_t poly, ca_ctx_t ctx) Checks if *poly* is the zero polynomial. .. function:: truth_t ca_poly_check_is_one(const ca_poly_t poly, ca_ctx_t ctx) Checks if *poly* is the constant polynomial 1. Arithmetic ------------------------------------------------------------------------------- .. function:: void _ca_poly_shift_left(ca_ptr res, ca_srcptr poly, slong len, slong n, ca_ctx_t ctx) void ca_poly_shift_left(ca_poly_t res, const ca_poly_t poly, slong n, ca_ctx_t ctx) Sets *res* to *poly* shifted *n* coefficients to the left; that is, multiplied by `x^n`. .. function:: void _ca_poly_shift_right(ca_ptr res, ca_srcptr poly, slong len, slong n, ca_ctx_t ctx) void ca_poly_shift_right(ca_poly_t res, const ca_poly_t poly, slong n, ca_ctx_t ctx) Sets *res* to *poly* shifted *n* coefficients to the right; that is, divided by `x^n`. .. function:: void ca_poly_neg(ca_poly_t res, const ca_poly_t src, ca_ctx_t ctx) Sets *res* to the negation of *src*. .. function:: void _ca_poly_add(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) void ca_poly_add(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) Sets *res* to the sum of *poly1* and *poly2*. .. function:: void _ca_poly_sub(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) void ca_poly_sub(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) Sets *res* to the difference of *poly1* and *poly2*. .. function:: void _ca_poly_mul(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) void ca_poly_mul(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) Sets *res* to the product of *poly1* and *poly2*. .. function:: void _ca_poly_mullow(ca_ptr C, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, slong n, ca_ctx_t ctx) void ca_poly_mullow(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, slong n, ca_ctx_t ctx) Sets *res* to the product of *poly1* and *poly2* truncated to length *n*. .. function:: void ca_poly_mul_ca(ca_poly_t res, const ca_poly_t poly, const ca_t c, ca_ctx_t ctx) Sets *res* to *poly* multiplied by the scalar *c*. .. function:: void ca_poly_div_ca(ca_poly_t res, const ca_poly_t poly, const ca_t c, ca_ctx_t ctx) Sets *res* to *poly* divided by the scalar *c*. .. function:: void _ca_poly_divrem_basecase(ca_ptr Q, ca_ptr R, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, const ca_t invB, ca_ctx_t ctx) int ca_poly_divrem_basecase(ca_poly_t Q, ca_poly_t R, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx) void _ca_poly_divrem(ca_ptr Q, ca_ptr R, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, const ca_t invB, ca_ctx_t ctx) int ca_poly_divrem(ca_poly_t Q, ca_poly_t R, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx) int ca_poly_div(ca_poly_t Q, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx) int ca_poly_rem(ca_poly_t R, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx) If the leading coefficient of *B* can be proved invertible, sets *Q* and *R* to the quotient and remainder of polynomial division of *A* by *B* and returns 1. If the leading coefficient cannot be proved invertible, returns 0. The underscore method takes a precomputed inverse of the leading coefficient of *B*. .. function:: void _ca_poly_pow_ui_trunc(ca_ptr res, ca_srcptr f, slong flen, ulong exp, slong len, ca_ctx_t ctx) void ca_poly_pow_ui_trunc(ca_poly_t res, const ca_poly_t poly, ulong exp, slong len, ca_ctx_t ctx) Sets *res* to *poly* raised to the power *exp*, truncated to length *len*. .. function:: void _ca_poly_pow_ui(ca_ptr res, ca_srcptr f, slong flen, ulong exp, ca_ctx_t ctx) void ca_poly_pow_ui(ca_poly_t res, const ca_poly_t poly, ulong exp, ca_ctx_t ctx) Sets *res* to *poly* raised to the power *exp*. Evaluation and composition ------------------------------------------------------------------------------- .. function:: void _ca_poly_evaluate_horner(ca_t res, ca_srcptr f, slong len, const ca_t x, ca_ctx_t ctx) void ca_poly_evaluate_horner(ca_t res, const ca_poly_t f, const ca_t a, ca_ctx_t ctx) void _ca_poly_evaluate(ca_t res, ca_srcptr f, slong len, const ca_t x, ca_ctx_t ctx) void ca_poly_evaluate(ca_t res, const ca_poly_t f, const ca_t a, ca_ctx_t ctx) Sets *res* to *f* evaluated at the point *a*. .. function:: void _ca_poly_compose_horner(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) void ca_poly_compose_horner(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) void _ca_poly_compose_divconquer(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) void ca_poly_compose_divconquer(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) void _ca_poly_compose(ca_ptr res, ca_srcptr poly1, slong len1, ca_srcptr poly2, slong len2, ca_ctx_t ctx) void ca_poly_compose(ca_poly_t res, const ca_poly_t poly1, const ca_poly_t poly2, ca_ctx_t ctx) Sets *res* to the composition of *poly1* with *poly2*. Derivative and integral ------------------------------------------------------------------------------- .. function:: void _ca_poly_derivative(ca_ptr res, ca_srcptr poly, slong len, ca_ctx_t ctx) void ca_poly_derivative(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx) Sets *res* to the derivative of *poly*. The underscore method needs one less coefficient than *len* for the output array. .. function:: void _ca_poly_integral(ca_ptr res, ca_srcptr poly, slong len, ca_ctx_t ctx) void ca_poly_integral(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx) Sets *res* to the integral of *poly*. The underscore method needs one more coefficient than *len* for the output array. Power series division ------------------------------------------------------------------------------- .. function:: void _ca_poly_inv_series(ca_ptr res, ca_srcptr f, slong flen, slong len, ca_ctx_t ctx) void ca_poly_inv_series(ca_poly_t res, const ca_poly_t f, slong len, ca_ctx_t ctx) Sets *res* to the power series inverse of *f* truncated to length *len*. .. function:: void _ca_poly_div_series(ca_ptr res, ca_srcptr f, slong flen, ca_srcptr g, slong glen, slong len, ca_ctx_t ctx) void ca_poly_div_series(ca_poly_t res, const ca_poly_t f, const ca_poly_t g, slong len, ca_ctx_t ctx) Sets *res* to the power series quotient of *f* and *g* truncated to length *len*. This function divides by zero if *g* has constant term zero; the user should manually remove initial zeros when an exact cancellation is required. Elementary functions ------------------------------------------------------------------------------- .. function:: void _ca_poly_exp_series(ca_ptr res, ca_srcptr f, slong flen, slong len, ca_ctx_t ctx) void ca_poly_exp_series(ca_poly_t res, const ca_poly_t f, slong len, ca_ctx_t ctx) Sets *res* to the power series exponential of *f* truncated to length *len*. .. function:: void _ca_poly_log_series(ca_ptr res, ca_srcptr f, slong flen, slong len, ca_ctx_t ctx) void ca_poly_log_series(ca_poly_t res, const ca_poly_t f, slong len, ca_ctx_t ctx) Sets *res* to the power series logarithm of *f* truncated to length *len*. .. function:: void _ca_poly_atan_series(ca_ptr res, ca_srcptr f, slong flen, slong len, ca_ctx_t ctx) void ca_poly_atan_series(ca_poly_t res, const ca_poly_t f, slong len, ca_ctx_t ctx) Sets *res* to the power series inverse tangent of *f* truncated to length *len*. Greatest common divisor ------------------------------------------------------------------------------- .. function:: slong _ca_poly_gcd_euclidean(ca_ptr res, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, ca_ctx_t ctx) int ca_poly_gcd_euclidean(ca_poly_t res, const ca_poly_t A, const ca_poly_t B, ca_ctx_t ctx) slong _ca_poly_gcd(ca_ptr res, ca_srcptr A, slong lenA, ca_srcptr B, slong lenB, ca_ctx_t ctx) int ca_poly_gcd(ca_poly_t res, const ca_poly_t A, const ca_poly_t g, ca_ctx_t ctx) Sets *res* to the GCD of *A* and *B* and returns 1 on success. On failure, returns 0 leaving the value of *res* arbitrary. The computation can fail if testing a leading coefficient for zero fails in the execution of the GCD algorithm. The output is normalized to be monic if it is not the zero polynomial. The underscore methods assume `\text{lenA} \ge \text{lenB} \ge 1`, and that both *A* and *B* have nonzero leading coefficient. They return the length of the GCD, or 0 if the computation fails. The *euclidean* version implements the standard Euclidean algorithm. The default version first checks for rational polynomials or attempts to certify numerically that the polynomials are coprime and otherwise falls back to an automatic choice of algorithm (currently only the Euclidean algorithm). Roots and factorization ------------------------------------------------------------------------------- .. function:: int ca_poly_factor_squarefree(ca_t c, ca_poly_vec_t fac, ulong * exp, const ca_poly_t F, ca_ctx_t ctx) Computes the squarefree factorization of *F*, giving a product `F = c f_1 f_2^2 \ldots f_n^n` where all `f_i` with `f_i \ne 1` are squarefree and pairwise coprime. The nontrivial factors `f_i` are written to *fac* and the corresponding exponents are written to *exp*. This algorithm can fail if GCD computation fails internally. Returns 1 on success and 0 on failure. .. function:: int ca_poly_squarefree_part(ca_poly_t res, const ca_poly_t poly, ca_ctx_t ctx) Sets *res* to the squarefree part of *poly*, normalized to be monic. This algorithm can fail if GCD computation fails internally. Returns 1 on success and 0 on failure. .. function:: void _ca_poly_set_roots(ca_ptr poly, ca_srcptr roots, const ulong * exp, slong n, ca_ctx_t ctx) void ca_poly_set_roots(ca_poly_t poly, ca_vec_t roots, const ulong * exp, ca_ctx_t ctx) Sets *poly* to the monic polynomial with the *n* roots given in the vector *roots*, with multiplicities given in the vector *exp*. In other words, this constructs the polynomial `(x-r_0)^{e_0} (x-r_1)^{e_1} \cdots (x-r_{n-1})^{e_{n-1}}`. Uses binary splitting. .. function:: int _ca_poly_roots(ca_ptr roots, ca_srcptr poly, slong len, ca_ctx_t ctx) int ca_poly_roots(ca_vec_t roots, ulong * exp, const ca_poly_t poly, ca_ctx_t ctx) Attempts to compute all complex roots of the given polynomial *poly*. On success, returns 1 and sets *roots* to a vector containing all the distinct roots with corresponding multiplicities in *exp*. On failure, returns 0 and leaves the values in *roots* arbitrary. The roots are returned in arbitrary order. Failure will occur if the leading coefficient of *poly* cannot be proved to be nonzero, if determining the correct multiplicities fails, or if the builtin algorithms do not have a means to represent the roots symbolically. The underscore method assumes that the polynomial is squarefree. The non-underscore method performs a squarefree factorization. Vectors of polynomials -------------------------------------------------------------------------------- .. type:: ca_poly_vec_struct .. type:: ca_poly_vec_t Represents a vector of polynomials. .. function:: ca_poly_struct * _ca_poly_vec_init(slong len, ca_ctx_t ctx) void ca_poly_vec_init(ca_poly_vec_t res, slong len, ca_ctx_t ctx) Initializes a vector with *len* polynomials. .. function:: void _ca_poly_vec_fit_length(ca_poly_vec_t vec, slong len, ca_ctx_t ctx) Allocates space for *len* polynomials in *vec*. .. function:: void ca_poly_vec_set_length(ca_poly_vec_t vec, slong len, ca_ctx_t ctx) Resizes *vec* to length *len*, zero-extending if needed. .. function:: void _ca_poly_vec_clear(ca_poly_struct * vec, slong len, ca_ctx_t ctx) void ca_poly_vec_clear(ca_poly_vec_t vec, ca_ctx_t ctx) Clears the vector *vec*. .. function:: void ca_poly_vec_append(ca_poly_vec_t vec, const ca_poly_t poly, ca_ctx_t ctx) Appends *poly* to the end of the vector *vec*. .. raw:: latex \newpage calcium-0.4.1/doc/source/ca_vec.rst000066400000000000000000000151441407704557200171700ustar00rootroot00000000000000.. _ca-vec: **ca_vec.h** -- vectors of real and complex numbers =============================================================================== A :type:`ca_vec_t` represents a vector of real or complex numbers, implemented as an array of coefficients of type :type:`ca_struct`. Most functions are provided in two versions: an underscore method which operates directly on pre-allocated arrays of coefficients (taking :type:`ca_ptr` and :type:`ca_srcptr` arguments), and a non-underscore method which takes :type:`ca_vec_t` input and performs automatic memory management. Unlike :type:`ca_poly_t`, a :type:`ca_vec_t` is not normalised by removing zero coefficients; it retains the exact length assigned by the user. Types, macros and constants ------------------------------------------------------------------------------- .. type:: ca_vec_struct .. type:: ca_vec_t Contains a pointer to an array of entries (*coeffs*), the used length (*length*), and the allocated size of the array (*alloc*). A *ca_vec_t* is defined as an array of length one of type *ca_vec_struct*, permitting an *ca_vec_t* to be passed by reference. .. macro:: ca_vec_entry(vec, i) Macro returning a pointer to entry *i* in the vector *vec*. The index must be in bounds. Memory management ------------------------------------------------------------------------------- .. function:: ca_ptr _ca_vec_init(slong len, ca_ctx_t ctx) Returns a pointer to an array of *len* coefficients initialized to zero. .. function:: void ca_vec_init(ca_vec_t vec, slong len, ca_ctx_t ctx) Initializes *vec* to a length *len* vector. All entries are set to zero. .. function:: void _ca_vec_clear(ca_ptr vec, slong len, ca_ctx_t ctx) Clears all *len* entries in *vec* and frees the pointer *vec* itself. .. function:: void ca_vec_clear(ca_vec_t vec, ca_ctx_t ctx) Clears the vector *vec*. .. function:: void _ca_vec_swap(ca_ptr vec1, ca_srcptr vec2, slong len, ca_ctx_t ctx) Swaps the entries in *vec1* and *vec2* efficiently. .. function:: void ca_vec_swap(ca_vec_t vec1, ca_vec_t vec2, ca_ctx_t ctx) Swaps the vectors *vec1* and *vec2* efficiently. Length ------------------------------------------------------------------------------- .. function:: slong ca_vec_length(const ca_vec_t vec, ca_ctx_t ctx) Returns the length of *vec*. .. function:: void _ca_vec_fit_length(ca_vec_t vec, slong len, ca_ctx_t ctx) Allocates space in *vec* for *len* elements. .. function:: void ca_vec_set_length(ca_vec_t vec, slong len, ca_ctx_t ctx) Sets the length of *vec* to *len*. If *vec* is shorter on input, it will be zero-extended. If *vec* is longer on input, it will be truncated. Assignment ------------------------------------------------------------------------------- .. function:: void _ca_vec_set(ca_ptr res, ca_srcptr src, slong len, ca_ctx_t ctx) Sets *res* to a copy of *src* of length *len*. .. function:: void ca_vec_set(ca_vec_t res, const ca_vec_t src, ca_ctx_t ctx) Sets *res* to a copy of *src*. Special vectors ------------------------------------------------------------------------------- .. function:: void _ca_vec_zero(ca_ptr res, slong len, ca_ctx_t ctx) Sets the *len* entries in *res* to zeros. .. function:: void ca_vec_zero(ca_vec_t res, slong len, ca_ctx_t ctx) Sets *res* to the length *len* zero vector. Input and output ------------------------------------------------------------------------------- .. function:: void ca_vec_print(const ca_vec_t vec, ca_ctx_t ctx) Prints *vec* to standard output. The coefficients are printed on separate lines. .. function:: void ca_vec_printn(const ca_vec_t poly, slong digits, ca_ctx_t ctx) Prints a decimal representation of *vec* with precision specified by *digits*. The coefficients are comma-separated and the whole list is enclosed in square brackets. List operations ------------------------------------------------------------------------------- .. function:: void ca_vec_append(ca_vec_t vec, const ca_t f, ca_ctx_t ctx) Appends *f* to the end of *vec*. Arithmetic ------------------------------------------------------------------------------- .. function:: void _ca_vec_neg(ca_ptr res, ca_srcptr src, slong len, ca_ctx_t ctx) .. function:: void ca_vec_neg(ca_vec_t res, const ca_vec_t src, ca_ctx_t ctx) Sets *res* to the negation of *src*. .. function:: void _ca_vec_add(ca_ptr res, ca_srcptr vec1, ca_srcptr vec2, slong len, ca_ctx_t ctx) .. function:: void _ca_vec_sub(ca_ptr res, ca_srcptr vec1, ca_srcptr vec2, slong len, ca_ctx_t ctx) Sets *res* to the sum or difference of *vec1* and *vec2*, all vectors having length *len*. .. function:: void _ca_vec_scalar_mul_ca(ca_ptr res, ca_srcptr src, slong len, const ca_t c, ca_ctx_t ctx) Sets *res* to *src* multiplied by *c*, all vectors having length *len*. .. function:: void _ca_vec_scalar_div_ca(ca_ptr res, ca_srcptr src, slong len, const ca_t c, ca_ctx_t ctx) Sets *res* to *src* divided by *c*, all vectors having length *len*. .. function:: void _ca_vec_scalar_addmul_ca(ca_ptr res, ca_srcptr src, slong len, const ca_t c, ca_ctx_t ctx) Adds *src* multiplied by *c* to the vector *res*, all vectors having length *len*. .. function:: void _ca_vec_scalar_submul_ca(ca_ptr res, ca_srcptr src, slong len, const ca_t c, ca_ctx_t ctx) Subtracts *src* multiplied by *c* from the vector *res*, all vectors having length *len*. Comparisons and properties --------------------------------------------------------------------------------- .. function:: truth_t _ca_vec_check_is_zero(ca_srcptr vec, slong len, ca_ctx_t ctx) Returns whether *vec* is the zero vector. Internal representation --------------------------------------------------------------------------------- .. function:: int _ca_vec_is_fmpq_vec(ca_srcptr vec, slong len, ca_ctx_t ctx) Checks if all elements of *vec* are structurally rational numbers. .. function:: int _ca_vec_fmpq_vec_is_fmpz_vec(ca_srcptr vec, slong len, ca_ctx_t ctx) Assuming that all elements of *vec* are structurally rational numbers, checks if all elements are integers. .. function:: void _ca_vec_fmpq_vec_get_fmpz_vec_den(fmpz * c, fmpz_t den, ca_srcptr vec, slong len, ca_ctx_t ctx) Assuming that all elements of *vec* are structurally rational numbers, converts them to a vector of integers *c* on a common denominator *den*. .. function:: void _ca_vec_set_fmpz_vec_div_fmpz(ca_ptr res, const fmpz * v, const fmpz_t den, slong len, ca_ctx_t ctx) Sets *res* to the rational vector given by numerators *v* and the common denominator *den*. .. raw:: latex \newpage calcium-0.4.1/doc/source/calcium.rst000066400000000000000000000116731407704557200173700ustar00rootroot00000000000000.. _calcium: **calcium.h** -- global definitions =============================================================================== Version ------------------------------------------------------------------------------- .. function:: const char * calcium_version(void) Returns a pointer to the version of the library as a string ``X.Y.Z``. Test code ------------------------------------------------------------------------------- .. function:: double calcium_test_multiplier(void) Multiplier for the number of iterations to run in each unit test. The value can be changed by setting the environment variable ``CALCIUM_TEST_MULTIPLIER``. The default value is 1.0. Triple-valued logic ------------------------------------------------------------------------------- This library uses two kinds of predicate functions: * Predicates with signature ``int foo_is_X(const foo_t x)`` return the usual C boolean values ``1`` for true and ``0`` for false, unless otherwise documented. Some functions may return ``0`` also when truth cannot be certified (this will be documented explicitly). * Predicates with signature ``truth_t foo_check_is_X(const foo_t x)`` check a mathematical property that may not be decidable (or may be too costly to decide). The return value is a :type:`truth_t` (``T_TRUE``, ``T_FALSE`` or ``T_UNKNOWN``). .. enum:: truth_t Represents one of the following truth values: .. macro:: T_TRUE .. macro:: T_FALSE .. macro:: T_UNKNOWN Warning: the constants ``T_TRUE`` and ``T_FALSE`` do not correspond to 1 and 0. It is erroneous to write, for example ``!t`` if ``t`` is a :type:`truth_t`. One should instead write ``t != T_TRUE``, ``t == T_FALSE``, etc. depending on whether the unknown case should be included or excluded. Flint, Arb and Antic types ------------------------------------------------------------------------------- The following types from Flint, Arb and Antic are used throughout Calcium. Although not included automatically by ``calcium.h``, we document them here for convenience. .. type:: slong Signed full-word integer (64 bits on a 64-bit system). .. type:: ulong Unsigned full-word integer (64 bits on a 64-bit system). .. type:: fmpz_t Flint integer. .. type:: fmpq_t Flint rational number. .. type:: fmpz_poly_t Flint dense univariate polynomial over the integers. .. type:: fmpq_poly_t Flint dense univariate polynomial over the rational numbers. .. type:: fmpz_mpoly_t Flint sparse multivariate integer polynomial. .. type:: fmpz_mpoly_ctx_t Context for Flint sparse multivariate integer polynomial (defining the number of variables and monomial order). .. type:: fmpz_mat_t Flint dense matrix over the integers. .. type:: fmpq_mat_t Flint dense matrix over the rational numbers. .. type:: arb_t Arb real number. .. type:: acb_t Arb complex number. .. type:: nf_t Antic number field. .. type:: nf_elem_t Antic number field element. Flint, Arb and Antic extras ------------------------------------------------------------------------------- Here we collect various utility methods for Flint, Arb and Antic types that are missing in those libraries. Some of these functions may be migrated upstream in the future. .. function:: ulong calcium_fmpz_hash(const fmpz_t x) Hash function for integers. The algorithm may change; presently, this simply extracts the low word (with sign). Input and output ------------------------------------------------------------------------------- .. type:: calcium_stream_struct .. type:: calcium_stream_t A stream object which can hold either a file pointer or a string (with automatic resizing). .. function:: void calcium_stream_init_file(calcium_stream_t out, FILE * fp) Initializes the stream *out* for writing to the file *fp*. The file can be *stdout*, *stderr*, or any file opened for writing by the user. .. function:: void calcium_stream_init_str(calcium_stream_t out) Initializes the stream *out* for writing to a string in memory. When finished, the user should free the string (the *s* member of *out* with ``flint_free()``). .. function:: void calcium_write(calcium_stream_t out, const char * s) Writes the string *s* to *out*. .. function:: void calcium_write_free(calcium_stream_t out, char * s) Writes *s* to *out* and then frees *s* by calling ``flint_free()``. .. function:: void calcium_write_si(calcium_stream_t out, slong x) void calcium_write_fmpz(calcium_stream_t out, const fmpz_t x) Writes the integer *x* to *out*. .. function:: void calcium_write_arb(calcium_stream_t out, const arb_t z, slong digits, ulong flags) void calcium_write_acb(calcium_stream_t out, const acb_t z, slong digits, ulong flags) Writes the Arb number *z* to *out*, showing *digits* digits and with the display style specified by *flags* (``ARB_STR_NO_RADIUS``, etc.). .. raw:: latex \newpage calcium-0.4.1/doc/source/conf.py000066400000000000000000000132651407704557200165170ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/stable/config # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # import os import sys sys.path.insert(0, os.path.abspath('../..')) sys.path.append(os.path.abspath(".")) sys.path.append(os.path.abspath('../../pycalcium')) # -- Project information ----------------------------------------------------- project = u'Calcium' copyright = u'2020-2021, Fredrik Johansson' author = u'Fredrik Johansson' # The short X.Y version version = u'' # The full version, including alpha/beta/rc tags release = u'' for _line in open("../../calcium.h").readlines(): if _line.startswith("#define CALCIUM_VERSION"): _i1 = _line.find('"') _i2 = _line.find('"', _i1 + 1) version = _line[_i1+1:_i2] release = version # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', ] primary_domain = 'c' default_role = 'math' # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'default' html_context = { 'css_files': ['_static/default.css'], } # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = { 'sidebarwidth' : 280, 'collapsiblesidebar': True, 'bodyfont': "'roboto', 'arial', sans-serif", 'headfont': "'roboto', 'arial', sans-serif", 'sidebarbtncolor': '#666', 'sidebarbgcolor': '#444', 'sidebarlinkcolor': '#ddd', 'relbarbgcolor': '#333', 'footerbgcolor': '#333', 'headbgcolor': '#fff', } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # The default sidebars (for documents that don't match any pattern) are # defined by theme itself. Builtin themes are using these templates by # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # # html_sidebars = {} # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'calciumdoc' # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). 'papersize': 'a4paper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. 'preamble': '\\usepackage{mathrsfs}\n\\usepackage{lmodern}\n\\setcounter{tocdepth}{2}\n\\urlstyle{tt}', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'calcium.tex', u'Calcium Documentation', u'Fredrik Johansson', 'manual'), ] latex_logo = "_static/ca2.pdf" latex_preamble = r""" \usepackage{amsmath,amssymb} \usepackage{breakurl} \setcounter{tocdepth}{2} """ # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'calcium', u'Calcium Documentation', [author], 1) ] # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'calcium', u'Calcium Documentation', author, 'Calcium', 'One line description of project.', 'Miscellaneous'), ] calcium-0.4.1/doc/source/examples.rst000066400000000000000000000313671407704557200175730ustar00rootroot00000000000000.. _examples: Example programs =============================================================================== .. highlight:: text The *examples* directory (https://github.com/fredrik-johansson/calcium/tree/master/examples) contains complete C programs illustrating use of Calcium. Running:: make examples will compile the programs and place the binaries in ``build/examples``. elementary.c ------------------------------------------------------------------------------- This program evaluates several elementary expressions. For some inputs, Calcium's arithmetic should produce a simplified result automatically. Some inputs do not yet automatically simplify as much as one might hope. Calcium may still able to prove that such a number is zero or nonzero; the output of :func:`ca_check_is_zero` is then ``T_TRUE`` or ``T_FALSE``. Sample output:: > build/examples/elementary >>> Exp(Pi*I) + 1 0 >>> Log(-1) / (Pi*I) 1 >>> Log(-I) / (Pi*I) -0.500000 {-1/2} >>> Log(1 / 10^123) / Log(100) -61.5000 {-123/2} >>> Log(1 + Sqrt(2)) / Log(3 + 2*Sqrt(2)) 0.500000 {1/2} >>> Sqrt(2)*Sqrt(3) - Sqrt(6) 0 >>> Exp(1+Sqrt(2)) * Exp(1-Sqrt(2)) / (Exp(1)^2) 1 >>> I^I - Exp(-Pi/2) 0 >>> Exp(Sqrt(3))^2 - Exp(Sqrt(12)) 0 >>> 2*Log(Pi*I) - 4*Log(Sqrt(Pi)) - Pi*I 0 >>> -I*Pi/8*Log(2/3-2*I/3)^2 + I*Pi/8*Log(2/3+2*I/3)^2 + Pi^2/12*Log(-1-I) + Pi^2/12*Log(-1+I) + Pi^2/12*Log(1/3-I/3) + Pi^2/12*Log(1/3+I/3) - Pi^2/48*Log(18) 0 >>> Sqrt(5 + 2*Sqrt(6)) - Sqrt(2) - Sqrt(3) 0e-1126 {a-c-d where a = 3.14626 [Sqrt(9.89898 {2*b+5})], b = 2.44949 [b^2-6=0], c = 1.73205 [c^2-3=0], d = 1.41421 [d^2-2=0]} >>> Is zero? T_TRUE >>> Sqrt(I) - (1+I)/Sqrt(2) 0e-1126 + 0e-1126*I {(2*a-b*c-b)/2 where a = 0.707107 + 0.707107*I [Sqrt(1.00000*I {c})], b = 1.41421 [b^2-2=0], c = I [c^2+1=0]} >>> Is zero? T_TRUE >>> Exp(Pi*Sqrt(163)) - (640320^3 + 744) -7.49927e-13 {a-262537412640768744 where a = 2.62537e+17 [Exp(40.1092 {b*c})], b = 3.14159 [Pi], c = 12.7671 [c^2-163=0]} >>> Erf(2*Log(Sqrt(1/2-Sqrt(2)/4))+Log(4)) - Erf(Log(2-Sqrt(2))) 0 cpu/wall(s): 0.022 0.022 virt/peak/res/peak(MB): 36.45 36.47 9.37 9.37 binet.c ------------------------------------------------------------------------------- This program computes the *n*-th Fibonacci number using Binet's formula `F_n = (\varphi^n - (1-\varphi)^n)/\sqrt{5}` where `\varphi = \tfrac{1}{2} (1+\sqrt{5})`. The program takes *n* as input. Sample output:: > build/examples/binet 250 7.89633e+51 {7896325826131730509282738943634332893686268675876375} cpu/wall(s): 0.002 0.001 virt/peak/res/peak(MB): 36.14 36.14 5.81 5.81 This illustrates exact arithmetic in algebraic number fields. The program also illustrates another aspect of Calcium arithmetic: evaluation limits. For example, trying to compute the index `n = 10^6` Fibonacci number hits an evaluation limit, so the value is not expanded to an explicit integer:: > build/examples/binet 1000000 1.95328e+208987 {(a*c-b*c)/5 where a = 4.36767e+208987 [Pow(1.61803 {(c+1)/2}, 1.00000e+6 {1000000})], b = 2.28955e-208988 [Pow(-0.618034 {(-c+1)/2}, 1.00000e+6 {1000000})], c = 2.23607 [c^2-5=0]} cpu/wall(s): 0.006 0.005 virt/peak/res/peak(MB): 36.14 36.14 9.05 9.05 Calling the program with ``-limit B n`` raises the bit evaluation limit to *B*. Setting this large enough allows `F_{10^6}` to expand to an integer (the following output has been truncated to avoid reproducing all 208988 digits):: > build/examples/binet -limit 10000000 1000000 1.95328e+208987 {1953282128...8242546875} cpu/wall(s): 0.229 0.242 virt/peak/res/peak(MB): 36.79 37.29 7.13 7.13 The exact mechanisms and interfaces for evaluation limits are still a work in progress. machin.c ------------------------------------------------------------------------------- This program checks several variations of Machin's formula .. math :: \frac{\pi}{4} = 4 \operatorname{atan}\left(\frac{1}{5}\right) - \operatorname{atan}\left(\frac{1}{239}\right) expressing `\pi` or logarithms of small integers in terms of arctangents or hyperbolic arctangents of rational numbers. The program actually evaluates `4 \operatorname{atan}\left(\tfrac{1}{5}\right) - \operatorname{atan}\left(\tfrac{1}{239}\right) - \tfrac{\pi}{4}` (etc.) and prints the result, which should be precisely 0, proving the identity. Inverse trigonometric functions are not yet implemented in Calcium, so the example program evaluates them using logarithms. Sample output:: > build/examples/machin [(1)*Atan(1/1) - Pi/4] = 0 [(1)*Atan(1/2) + (1)*Atan(1/3) - Pi/4] = 0 [(2)*Atan(1/2) + (-1)*Atan(1/7) - Pi/4] = 0 [(2)*Atan(1/3) + (1)*Atan(1/7) - Pi/4] = 0 [(4)*Atan(1/5) + (-1)*Atan(1/239) - Pi/4] = 0 [(1)*Atan(1/2) + (1)*Atan(1/5) + (1)*Atan(1/8) - Pi/4] = 0 [(1)*Atan(1/3) + (1)*Atan(1/4) + (1)*Atan(1/7) + (1)*Atan(1/13) - Pi/4] = 0 [(12)*Atan(1/49) + (32)*Atan(1/57) + (-5)*Atan(1/239) + (12)*Atan(1/110443) - Pi/4] = 0 [(14)*Atanh(1/31) + (10)*Atanh(1/49) + (6)*Atanh(1/161) - Log(2)] = 0 [(22)*Atanh(1/31) + (16)*Atanh(1/49) + (10)*Atanh(1/161) - Log(3)] = 0 [(32)*Atanh(1/31) + (24)*Atanh(1/49) + (14)*Atanh(1/161) - Log(5)] = 0 [(144)*Atanh(1/251) + (54)*Atanh(1/449) + (-38)*Atanh(1/4801) + (62)*Atanh(1/8749) - Log(2)] = 0 [(228)*Atanh(1/251) + (86)*Atanh(1/449) + (-60)*Atanh(1/4801) + (98)*Atanh(1/8749) - Log(3)] = 0 [(334)*Atanh(1/251) + (126)*Atanh(1/449) + (-88)*Atanh(1/4801) + (144)*Atanh(1/8749) - Log(5)] = 0 [(404)*Atanh(1/251) + (152)*Atanh(1/449) + (-106)*Atanh(1/4801) + (174)*Atanh(1/8749) - Log(7)] = 0 cpu/wall(s): 0.016 0.016 virt/peak/res/peak(MB): 35.57 35.57 8.80 8.80 swinnerton_dyer_poly.c ------------------------------------------------------------------------------- This program computes the coefficients of the Swinnerton-Dyer polynomial .. math :: S_n = \prod (x \pm \sqrt{2} \pm \sqrt{3} \pm \sqrt{5} \pm \ldots \pm \sqrt{p_n}) where `p_n` denotes the `n`-th prime number and all combinations of signs are taken. This polynomial has degree `2^n`. The polynomial is expanded from its roots using naive polynomial multiplication over :type:`ca_t` coefficients. There are far more efficient ways to construct this polynomial; this program simply illustrates that arithmetic in multivariate number fields works smoothly. The program prints the coefficients of `S_n`, from the constant term to the coefficient of `x^{2^n}`. Sample output:: > build/examples/swinnerton_dyer_poly 3 576 0 -960 0 352 0 -40 0 1 cpu/wall(s): 0.002 0.002 virt/peak/res/peak(MB): 35.07 35.11 5.40 5.40 A big benchmark problem (output truncated):: > build/examples/swinnerton_dyer_poly 10 4.35675e+809 {43567450015...212890625} 0 ... 0 1 cpu/wall(s): 9.296 9.307 virt/peak/res/peak(MB): 38.95 38.95 10.01 10.01 huge_expr.c ------------------------------------------------------------------------------- This program proves equality of two complicated algebraic numbers. More precisely, the program verifies that `N = -(1 - |M|^2)^2` where *N* and *M* are given by huge symbolic expressions involving nested square roots (about 7000 operations in total). By default, the program runs the computation using :type:`qqbar_t` arithmetic:: > build/examples/huge_expr Evaluating N... cpu/wall(s): 7.205 7.206 Evaluating M... cpu/wall(s): 0.933 0.934 Evaluating E = -(1-|M|^2)^2... cpu/wall(s): 0.391 0.391 N ~ -0.16190853053311203695842869991458578203473645660641 E ~ -0.16190853053311203695842869991458578203473645660641 Testing E = N... cpu/wall(s): 0.001 0 Equal = T_TRUE Total: cpu/wall(s): 8.53 8.531 virt/peak/res/peak(MB): 54.50 64.56 24.64 34.61 To run the computation using :type:`ca_t` arithmetic instead, pass the -ca flag:: > build/examples/huge_expr -ca Evaluating N... cpu/wall(s): 0.193 0.193 Evaluating M... cpu/wall(s): 0.024 0.024 Evaluating E = -(1-|M|^2)^2... cpu/wall(s): 0.008 0.009 N ~ -0.16190853053311203695842869991458578203473645660641 E ~ -0.16190853053311203695842869991458578203473645660641 Testing E = N... cpu/wall(s): 8.017 8.019 Equal = T_TRUE Total: cpu/wall(s): 8.243 8.246 virt/peak/res/peak(MB): 61.67 65.29 33.97 37.54 This simplification problem was posted in a help request for Sage (https://ask.sagemath.org/question/52653). The C code has been generated from the symbolic expressions using a Python script. hilbert_matrix.c ------------------------------------------------------------------------------- This program constructs the Hilbert matrix `H_n = (1/(i+j-1))_{i=1,j=1}^n`, computes its eigenvalues `\lambda_1, \ldots, \lambda_n`, as exact algebraic numbers, and verifies the exact trace and determinant formulas .. math :: \lambda_1 + \lambda_2 + \ldots + \lambda_n = \operatorname{tr}(H_n), \quad \lambda_1 \lambda_2 \cdots \lambda_n = \operatorname{det}(H_n). Sample output:: > build/examples/hilbert_matrix 6 Trace: 1.87821 {6508/3465} 1.87821 {6508/3465} Equal: T_TRUE Det: 5.36730e-18 {1/186313420339200000} 5.36730e-18 {1/186313420339200000} Equal: T_TRUE cpu/wall(s): 0.07 0.069 virt/peak/res/peak(MB): 36.56 36.66 9.69 9.69 The program accepts the following optional arguments: * With ``-vieta``, force use of Vieta's formula internally (by default, Calcium uses Vieta's formulas when working with algebraic conjugates, but only up to some bound on the degree). * With ``-novieta``, force Calcium not to use Vieta's formulas internally. * With ``-qqbar``, do a similar computation using :type:`qqbar_t` arithmetic. dft.c ------------------------------------------------------------------------------- This program demonstrates the discrete Fourier transform (DFT) in exact arithmetic. For the input vector `\textbf{x} = (x_n)_{n=0}^{N-1}`, it verifies the identity .. math :: \textbf{x} - \operatorname{DFT}^{-1}(\operatorname{DFT}(\textbf{x})) = 0 where .. math :: \operatorname{DFT}(\textbf{x})_n = \sum_{k=0}^{N-1} \omega^{-kn} x_k, \quad \operatorname{DFT}^{-1}(\textbf{x})_n = \frac{1}{N} \sum_{k=0}^{N-1} \omega^{kn} x_k, \quad \omega = e^{2 \pi i / N}. The program computes the DFT by naive `O(N^2)` summation (not using FFT). It uses repeated multiplication of `\omega` to precompute an array of roots of unity `1,\omega,\omega^2,\ldots,\omega^{2N-1}` for use in both the DFT and the inverse DFT. Usage:: build/examples/dft [-verbose] [-input i] [-limit B] [-timing T] N The required parameter ``N`` selects the length of the vector. The optional flag ``-verbose`` chooses whether to print the arrays. The optional parameter ``-timing T`` selects a timing method (default = 0). * 0: run the computation once and time it * 1: run the computation repeatedly if needed to get an accurate timing, creating a new context object for each iteration so that fields are not cached * 2: run the computation once, then run the computation at least one more time (repeatedly if needed to get an accurate timing), recycling the same context object to measure the performance with cached fields The optional parameter ``-input i`` selects an input sequence (default = 0). * 0: `x_n = n+2` * 1: `x_n = \sqrt{n+2}` * 2: `x_n = \log(n+2)` * 3: `x_n = e^{2 \pi i / (n+2)}` The optional parameter ``-limit B`` sets the internal degree limit for algebraic numbers. Sample output:: > build/examples/dft 4 -input 1 -verbose DFT benchmark, length N = 4 [x] = 1.41421 {a where a = 1.41421 [a^2-2=0]} 1.73205 {a where a = 1.73205 [a^2-3=0]} 2 2.23607 {a where a = 2.23607 [a^2-5=0]} DFT([x]) = 7.38233 {a+b+c+2 where a = 2.23607 [a^2-5=0], b = 1.73205 [b^2-3=0], c = 1.41421 [c^2-2=0]} -0.585786 + 0.504017*I {a*d-b*d+c-2 where a = 2.23607 [a^2-5=0], b = 1.73205 [b^2-3=0], c = 1.41421 [c^2-2=0], d = I [d^2+1=0]} -0.553905 {-a-b+c+2 where a = 2.23607 [a^2-5=0], b = 1.73205 [b^2-3=0], c = 1.41421 [c^2-2=0]} -0.585786 - 0.504017*I {-a*d+b*d+c-2 where a = 2.23607 [a^2-5=0], b = 1.73205 [b^2-3=0], c = 1.41421 [c^2-2=0], d = I [d^2+1=0]} IDFT(DFT([x])) = 1.41421 {c where a = 2.23607 [a^2-5=0], b = 1.73205 [b^2-3=0], c = 1.41421 [c^2-2=0], d = I [d^2+1=0]} 1.73205 {b where a = 2.23607 [a^2-5=0], b = 1.73205 [b^2-3=0], c = 1.41421 [c^2-2=0], d = I [d^2+1=0]} 2 2.23607 {a where a = 2.23607 [a^2-5=0], b = 1.73205 [b^2-3=0], c = 1.41421 [c^2-2=0], d = I [d^2+1=0]} [x] - IDFT(DFT([x])) = 0 (= 0 T_TRUE) 0 (= 0 T_TRUE) 0 (= 0 T_TRUE) 0 (= 0 T_TRUE) cpu/wall(s): 0.009 0.009 virt/peak/res/peak(MB): 36.28 36.28 9.14 9.14 .. raw:: latex \newpage calcium-0.4.1/doc/source/fexpr.rst000066400000000000000000000556551407704557200171070ustar00rootroot00000000000000.. _fexpr: **fexpr.h** -- flat-packed symbolic expressions =============================================================================== This module supports working with symbolic expressions. Introduction ----------------------------------------------------------------------- Formally, a symbolic expression is either: * An atom, being one of the following: * An integer, for example 0 or -34. * A symbol, for example ``x``, ``Mul``, ``SomeUserNamedSymbol``. Symbols should be valid C identifiers (containing only the characters ``A-Z``, ``a-z``, ``0-9``, ``_``, and not starting with a digit). * A string, for example ``"Hello, world!"``. For the moment, we only consider ASCII strings, but there is no obstacle in principle to supporting UTF-8. * A non-atomic expression, representing a function call `e_0(e_1, \ldots, e_n)` where `e_0, \ldots, e_n` are symbolic expressions. The meaning of an expression depends on the interpretation of symbols in a given context. For example, with a standard intepretation (used within Calcium) of the symbols ``Mul``, ``Add`` and ``Neg``, the expression ``Mul(3, Add(Neg(x), y))`` encodes the formula `3 \cdot ((-x)+y)` where ``x`` and ``y`` are symbolic variables. See :ref:`fexpr-builtin` for documentation of builtin symbols. Computing and embedding data ....................................................................... Symbolic expressions are usually not the best data structure to use directly for heavy-duty computations. Functions acting on symbolic expressions will typically convert to a dedicated data structure (e.g. polynomials) internally and (optionally) convert the final result back to a symbolic expression. Symbolic expressions do not allow embedding arbitrary binary objects such as Flint/Arb/Antic/Calcium types as atoms. This is done on purpose to make symbolic expressions easy to use as a data exchange format. To embed an object in an expression, one has the following options: * Represent the object structurally using atoms supported natively by symbolic expressions (for example, an integer polynomial can be represented as a list of coefficients or as an arithmetic expression tree). * Introduce a dummy symbol to represent the object, maintaining an external translation table mapping this symbol to the intended value. * Encode the object using a string or symbol name. This is generally not recommended, as it requires parsing; properly used, symbolic expressions have the benefit of being able to represent the parsed structure. Flat-packed representation ....................................................................... Symbolic expressions are often implemented using trees of pointers (often together with hash tables for uniqueness), requiring some form of memory management. The :type:`fexpr_t` type, by contrast, stores a symbolic expression using a "flat-packed" representation without internal pointers. The expression data is just an array of words (``ulong``). The first word is a header encoding type information (whether the expression is a function call or an atom, and the type of the atom) and the total number of words in the expression. For atoms, the data is stored either in the header word itself (small integers and short symbols/strings) or in the following words. For function calls, the header is followed by the expressions `e_0`, ..., `e_n` packed contiguously in memory. Pros: * Memory management is trivial. * Copying an expression is just copying an array of words. * Comparing expressions for equality is just comparing arrays of words. * Merging expressions is basically just concatenating arrays of words. * Expression data can be shared freely in binary form between threads and even between machines (as long as all machines have the same word size and endianness). Cons: * Repeated instances of the same subexpression cannot share memory (a workaround is to introduce local dummy symbols for repeated subexpressions). * Extracting a subexpression for modification generally requires making a complete copy of that subxepression (however, for read-only access to subexpressions, one can use "view" expressions which have zero overhead). * Manipulating a part of an expression generally requires rebuilding the whole expression. * Building an expression incrementally is typically `O(n^2)`. As a workaround, it is a good idea to work with balanced (low-depth) expressions and try to construct an expression in one go (for example, to create a sum, create a single ``Add`` expression with many arguments instead of chaining binary ``Add`` operations). Types and macros ------------------------------------------------------------------------------- .. type:: fexpr_struct .. type:: fexpr_t An *fexpr_struct* consists of a pointer to an array of words along with a record of the number of allocated words. An *fexpr_t* is defined as an array of length one of type *fexpr_struct*, permitting an *fexpr_t* to be passed by reference. .. type:: fexpr_ptr Alias for ``fexpr_struct *``, used for arrays of expressions. .. type:: fexpr_srcptr Alias for ``const fexpr_struct *``, used for arrays of expressions when passed as constant input to functions. .. type:: fexpr_vec_struct .. type:: fexpr_vec_t A type representing a vector of expressions with managed length. The structure contains an :type:`fexpr_ptr` *entries* for the entries, an integer *length* (the size of the vector), and an integer *alloc* (the number of allocated entries). .. macro:: fexpr_vec_entry(vec, i) Returns a pointer to entry *i* in the vector *vec*. Memory management ------------------------------------------------------------------------------- .. function:: void fexpr_init(fexpr_t expr) Initializes *expr* for use. Its value is set to the atomic integer 0. .. function:: void fexpr_clear(fexpr_t expr) Clears *expr*, freeing its allocated memory. .. function:: fexpr_ptr _fexpr_vec_init(slong len) Returns a heap-allocated vector of *len* initialized expressions. .. function:: void _fexpr_vec_clear(fexpr_ptr vec, slong len) Clears the *len* expressions in *vec* and frees *vec* itself. .. function:: void fexpr_fit_size(fexpr_t expr, slong size) Ensures that *expr* has room for *size* words. .. function:: void fexpr_set(fexpr_t res, const fexpr_t expr) Sets *res* to the a copy of *expr*. .. function:: void fexpr_swap(fexpr_t a, fexpr_t b) Swaps *a* and *b* efficiently. Size information ------------------------------------------------------------------------------- .. function:: slong fexpr_depth(const fexpr_t expr) Returns the depth of *expr* as a symbolic expression tree. .. function:: slong fexpr_num_leaves(const fexpr_t expr) Returns the number of leaves (atoms, counted with repetition) in the expression *expr*. .. function:: slong fexpr_size(const fexpr_t expr) Returns the number of words in the internal representation of *expr*. .. function:: slong fexpr_size_bytes(const fexpr_t expr) Returns the number of bytes in the internal representation of *expr*. The count excludes the size of the structure itself. Add ``sizeof(fexpr_struct)`` to get the size of the object as a whole. .. function:: slong fexpr_allocated_bytes(const fexpr_t expr) Returns the number of allocated bytes in the internal representation of *expr*. The count excludes the size of the structure itself. Add ``sizeof(fexpr_struct)`` to get the size of the object as a whole. Comparisons ------------------------------------------------------------------------------- .. function:: int fexpr_equal(const fexpr_t a, const fexpr_t b) Checks if *a* and *b* are exactly equal as expressions. .. function:: int fexpr_equal_si(const fexpr_t expr, slong c) .. function:: int fexpr_equal_ui(const fexpr_t expr, ulong c) Checks if *expr* is an atomic integer exactly equal to *c*. .. function:: ulong fexpr_hash(const fexpr_t expr) Returns a hash of the expression *expr*. .. function:: int fexpr_cmp_fast(const fexpr_t a, const fexpr_t b) Compares *a* and *b* using an ordering based on the internal representation, returning -1, 0 or 1. This can be used, for instance, to maintain sorted arrays of expressions for binary search; the sort order has no mathematical significance. Atoms ------------------------------------------------------------------------------- .. function:: int fexpr_is_integer(const fexpr_t expr) Returns whether *expr* is an atomic integer .. function:: int fexpr_is_symbol(const fexpr_t expr) Returns whether *expr* is an atomic symbol. .. function:: int fexpr_is_string(const fexpr_t expr) Returns whether *expr* is an atomic string. .. function:: int fexpr_is_atom(const fexpr_t expr) Returns whether *expr* is any atom. .. function:: void fexpr_zero(fexpr_t res) Sets *res* to the atomic integer 0. .. function:: int fexpr_is_zero(const fexpr_t expr) Returns whether *expr* is the atomic integer 0. .. function:: int fexpr_is_neg_integer(const fexpr_t expr) Returns whether *expr* is any negative atomic integer. .. function:: void fexpr_set_si(fexpr_t res, slong c) void fexpr_set_ui(fexpr_t res, ulong c) void fexpr_set_fmpz(fexpr_t res, const fmpz_t c) Sets *res* to the atomic integer *c*. .. function:: void fexpr_get_fmpz(fmpz_t res, const fexpr_t expr) Sets *res* to the atomic integer in *expr*. This aborts if *expr* is not an atomic integer. .. function:: void fexpr_set_symbol_builtin(fexpr_t res, slong id) Sets *res* to the builtin symbol with internal index *id* (see :ref:`fexpr-builtin`). .. function:: int fexpr_is_builtin_symbol(const fexpr_t expr, slong id) Returns whether *expr* is the builtin symbol with index *id* (see :ref:`fexpr-builtin`). .. function:: int fexpr_is_any_builtin_symbol(const fexpr_t expr) Returns whether *expr* is any builtin symbol (see :ref:`fexpr-builtin`). .. function:: void fexpr_set_symbol_str(fexpr_t res, const char * s) Sets *res* to the symbol given by *s*. .. function:: char * fexpr_get_symbol_str(const fexpr_t expr) Returns the symbol in *expr* as a string. The string must be freed with :func:`flint_free`. This aborts if *expr* is not an atomic symbol. .. function:: void fexpr_set_string(fexpr_t res, const char * s) Sets *res* to the atomic string *s*. .. function:: char * fexpr_get_string(const fexpr_t expr) Assuming that *expr* is an atomic string, returns a copy of this string. The string must be freed with :func:`flint_free`. Input and output ------------------------------------------------------------------------ .. function:: void fexpr_write(calcium_stream_t stream, const fexpr_t expr) Writes *expr* to *stream*. .. function:: void fexpr_print(const fexpr_t expr) Prints *expr* to standard output. .. function:: char * fexpr_get_str(const fexpr_t expr) Returns a string representation of *expr*. The string must be freed with :func:`flint_free`. Warning: string literals appearing in expressions are currently not escaped. LaTeX output ------------------------------------------------------------------------ .. function:: void fexpr_write_latex(calcium_stream_t stream, const fexpr_t expr, ulong flags) Writes the LaTeX representation of *expr* to *stream*. .. function:: void fexpr_print_latex(const fexpr_t expr, ulong flags) Prints the LaTeX representation of *expr* to standard output. .. function:: char * fexpr_get_str_latex(const fexpr_t expr, ulong flags) Returns a string of the LaTeX representation of *expr*. The string must be freed with :func:`flint_free`. Warning: string literals appearing in expressions are currently not escaped. The *flags* parameter allows specifying options for LaTeX output. The following flags are supported: .. macro:: FEXPR_LATEX_SMALL Generate more compact formulas, most importantly by printing fractions inline as `p/q` instead of as `\displaystyle{\frac{p}{q}}`. This flag is automatically activated within subscripts and superscripts and in certain other parts of formulas. .. macro:: FEXPR_LATEX_LOGIC Use symbols for logical operators such as Not, And, Or, which by default are rendered as words for legibility. Function call structure ------------------------------------------------------------------------ .. function:: slong fexpr_nargs(const fexpr_t expr) Returns the number of arguments *n* in the function call `f(e_1,\ldots,e_n)` represented by *expr*. If *expr* is an atom, returns -1. .. function:: void fexpr_func(fexpr_t res, const fexpr_t expr) Assuming that *expr* represents a function call `f(e_1,\ldots,e_n)`, sets *res* to the function expression *f*. .. function:: void fexpr_view_func(fexpr_t view, const fexpr_t expr) As :func:`fexpr_func`, but sets *view* to a shallow view instead of copying the expression. The variable *view* must not be initialized before use or cleared after use, and *expr* must not be modified or cleared as long as *view* is in use. .. function:: void fexpr_arg(fexpr_t res, const fexpr_t expr, slong i) Assuming that *expr* represents a function call `f(e_1,\ldots,e_n)`, sets *res* to the argument `e_{i+1}`. Note that indexing starts from 0. The index must be in bounds, with `0 \le i < n`. .. function:: void fexpr_view_arg(fexpr_t view, const fexpr_t expr, slong i) As :func:`fexpr_arg`, but sets *view* to a shallow view instead of copying the expression. The variable *view* must not be initialized before use or cleared after use, and *expr* must not be modified or cleared as long as *view* is in use. .. function:: void fexpr_view_next(fexpr_t view) Assuming that *view* is a shallow view of a function argument `e_i` in a function call `f(e_1,\ldots,e_n)`, sets *view* to a view of the next argument `e_{i+1}`. This function can be called when *view* refers to the last argument `e_n`, provided that *view* is not used afterwards. This function can also be called when *view* refers to the function *f*, in which case it will make *view* point to `e_1`. .. function:: int fexpr_is_builtin_call(const fexpr_t expr, slong id) Returns whether *expr* has the form `f(\ldots)` where *f* is a builtin function defined by *id* (see :ref:`fexpr-builtin`). .. function:: int fexpr_is_any_builtin_call(const fexpr_t expr) Returns whether *expr* has the form `f(\ldots)` where *f* is any builtin function (see :ref:`fexpr-builtin`). Composition ------------------------------------------------------------------------ .. function:: void fexpr_call0(fexpr_t res, const fexpr_t f) void fexpr_call1(fexpr_t res, const fexpr_t f, const fexpr_t x1) void fexpr_call2(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2) void fexpr_call3(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2, const fexpr_t x3) void fexpr_call4(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2, const fexpr_t x3, const fexpr_t x4) void fexpr_call_vec(fexpr_t res, const fexpr_t f, fexpr_srcptr args, slong len) Creates the function call `f(x_1,\ldots,x_n)`. The *vec* version takes the arguments as an array *args* and *n* is given by *len*. Warning: aliasing between inputs and outputs is not implemented. .. function:: void fexpr_call_builtin1(fexpr_t res, slong f, const fexpr_t x1) void fexpr_call_builtin2(fexpr_t res, slong f, const fexpr_t x1, const fexpr_t x2) Creates the function call `f(x_1,\ldots,x_n)`, where *f* defines a builtin symbol. Subexpressions and replacement ------------------------------------------------------------------------ .. function:: int fexpr_contains(const fexpr_t expr, const fexpr_t x) Returns whether *expr* contains the expression *x* as a subexpression (this includes the case where *expr* and *x* are equal). .. function:: int fexpr_replace(fexpr_t res, const fexpr_t expr, const fexpr_t x, const fexpr_t y) Sets *res* to the expression *expr* with all occurrences of the subexpression *x* replaced by the expression *y*. Returns a boolean value indicating whether any replacements have been performed. Aliasing is allowed between *res* and *expr* but not between *res* and *x* or *y*. .. function:: int fexpr_replace2(fexpr_t res, const fexpr_t expr, const fexpr_t x1, const fexpr_t y1, const fexpr_t x2, const fexpr_t y2) Like :func:`fexpr_replace`, but simultaneously replaces *x1* by *y1* and *x2* by *y2*. .. function:: int fexpr_replace_vec(fexpr_t res, const fexpr_t expr, const fexpr_vec_t xs, const fexpr_vec_t ys) Sets *res* to the expression *expr* with all occurrences of the subexpressions given by entries in *xs* replaced by the corresponding expressions in *ys*. It is required that *xs* and *ys* have the same length. Returns a boolean value indicating whether any replacements have been performed. Aliasing is allowed between *res* and *expr* but not between *res* and the entries of *xs* or *ys*. Arithmetic expressions ------------------------------------------------------------------------ .. function:: void fexpr_set_fmpq(fexpr_t res, const fmpq_t x) Sets *res* to the rational number *x*. This creates an atomic integer if the denominator of *x* is one, and otherwise creates a division expression. .. function:: void fexpr_set_arf(fexpr_t res, const arf_t x) void fexpr_set_d(fexpr_t res, double x) Sets *res* to an expression for the value of the floating-point number *x*. NaN is represented as ``Undefined``. For a regular value, this creates an atomic integer or a rational fraction if the exponent is small, and otherwise creates an expression of the form ``Mul(m, Pow(2, e))``. .. function:: void fexpr_set_re_im_d(fexpr_t res, double x, double y) Sets *res* to an expression for the complex number with real part *x* and imaginary part *y*. .. function:: void fexpr_neg(fexpr_t res, const fexpr_t a) void fexpr_add(fexpr_t res, const fexpr_t a, const fexpr_t b) void fexpr_sub(fexpr_t res, const fexpr_t a, const fexpr_t b) void fexpr_mul(fexpr_t res, const fexpr_t a, const fexpr_t b) void fexpr_div(fexpr_t res, const fexpr_t a, const fexpr_t b) void fexpr_pow(fexpr_t res, const fexpr_t a, const fexpr_t b) Constructs an arithmetic expression with given arguments. No simplifications whatsoever are performed. .. function:: int fexpr_is_arithmetic_operation(const fexpr_t expr) Returns whether *expr* is of the form `f(e_1,\ldots,e_n)` where *f* is one of the arithmetic operators ``Pos``, ``Neg``, ``Add``, ``Sub``, ``Mul``, ``Div``. .. function:: void fexpr_arithmetic_nodes(fexpr_vec_t nodes, const fexpr_t expr) Sets *nodes* to a vector of subexpressions of *expr* such that *expr* is an arithmetic expression with *nodes* as leaves. More precisely, *expr* will be constructed out of nested application the arithmetic operators ``Pos``, ``Neg``, ``Add``, ``Sub``, ``Mul``, ``Div`` with integers and expressions in *nodes* as leaves. Powers ``Pow`` with an atomic integer exponent are also allowed. The nodes are output without repetition but are not automatically sorted in a canonical order. .. function:: int fexpr_get_fmpz_mpoly_q(fmpz_mpoly_q_t res, const fexpr_t expr, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx) Sets *res* to the expression *expr* as a formal rational function of the subexpressions in *vars*. The vector *vars* must have the same length as the number of variables specified in *ctx*. To build *vars* automatically for a given expression, :func:`fexpr_arithmetic_nodes` may be used. Returns 1 on success and 0 on failure. Failure can occur for the following reasons: * A subexpression is encountered that cannot be interpreted as an arithmetic operation and does not appear (exactly) in *vars*. * Overflow (too many terms or too large exponent). * Division by zero (a zero denominator is encountered). It is important to note that this function views *expr* as a formal rational function with *vars* as formal indeterminates. It does thus not check for algebraic relations between *vars* and can implicitly divide by zero if *vars* are not algebraically independent. .. function:: void fexpr_set_fmpz_mpoly(fexpr_t res, const fmpz_mpoly_t poly, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx) void fexpr_set_fmpz_mpoly_q(fexpr_t res, const fmpz_mpoly_q_t frac, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx) Sets *res* to an expression for the multivariate polynomial *poly* (or rational function *frac*), using the expressions in *vars* as the variables. The length of *vars* must agree with the number of variables in *ctx*. If *NULL* is passed for *vars*, a default choice of symbols is used. .. function:: int fexpr_expanded_normal_form(fexpr_t res, const fexpr_t expr, ulong flags) Sets *res* to *expr* converted to expanded normal form viewed as a formal rational function with its non-arithmetic subexpressions as terminal nodes. This function first computes nodes with :func:`fexpr_arithmetic_nodes`, sorts the nodes, evaluates to a rational function with :func:`fexpr_get_fmpz_mpoly_q`, and then converts back to an expression with :func:`fexpr_set_fmpz_mpoly_q`. Optional *flags* are reserved for future use. Vectors ------------------------------------------------------------------------ .. function:: void fexpr_vec_init(fexpr_vec_t vec, slong len) Initializes *vec* to a vector of length *len*. All entries are set to the atomic integer 0. .. function:: void fexpr_vec_clear(fexpr_vec_t vec) Clears the vector *vec*. .. function:: void fexpr_vec_print(const fexpr_vec_t vec) Prints *vec* to standard output. .. function:: void fexpr_vec_swap(fexpr_vec_t x, fexpr_vec_t y) Swaps *x* and *y* efficiently. .. function:: void fexpr_vec_fit_length(fexpr_vec_t vec, slong len) Ensures that *vec* has space for *len* entries. .. function:: void fexpr_vec_set(fexpr_vec_t dest, const fexpr_vec_t src) Sets *dest* to a copy of *src*. .. function:: void fexpr_vec_append(fexpr_vec_t vec, const fexpr_t expr) Appends *expr* to the end of the vector *vec*. .. function:: slong fexpr_vec_insert_unique(fexpr_vec_t vec, const fexpr_t expr) Inserts *expr* without duplication into vec, returning its position. If this expression already exists, *vec* is unchanged. If this expression does not exist in *vec*, it is appended. .. function:: void fexpr_vec_set_length(fexpr_vec_t vec, slong len) Sets the length of *vec* to *len*, truncating or zero-extending as needed. .. function:: void _fexpr_vec_sort_fast(fexpr_ptr vec, slong len) Sorts the *len* entries in *vec* using the comparison function :func:`fexpr_cmp_fast`. .. raw:: latex \newpage calcium-0.4.1/doc/source/fexpr_builtin.rst000066400000000000000000000645121407704557200206250ustar00rootroot00000000000000.. _fexpr-builtin: **fexpr_builtin.h** -- builtin symbols =============================================================================== This module defines symbol names with a predefined meaning for use in symbolic expressions. These symbols will eventually all support LaTeX rendering as well as symbolic and numerical evaluation (where applicable). By convention, all builtin symbol names are at least two characters long and start with an uppercase letter. Single-letter symbol names and symbol names beginning with a lowercase letter are reserved for variables. For any builtin symbol name ``Symbol``, the header file ``fexpr_builtin.h`` defines a C constant ``FEXPR_Symbol`` as an index to a builtin symbol table. The symbol will be documented as ``Symbol`` below. C helper functions ------------------------------------------------------------------------ .. function:: slong fexpr_builtin_lookup(const char * s) Returns the internal index used to encode the builtin symbol with name *s* in expressions. If *s* is not the name of a builtin symbol, returns -1. .. function:: const char * fexpr_builtin_name(slong n) Returns a read-only pointer for a string giving the name of the builtin symbol with index *n*. .. function:: slong fexpr_builtin_length(void) Returns the number of builtin symbols. Variables and iteration ------------------------------------------------------------------------ Expressions involving the following symbols have a special role in binding variables. .. macro:: For Generator expression. This is a syntactical construct which does not represent a mathematical object on its own. In general, ``For(x, ...)`` defines the symbol ``x`` as a locally bound variable in the scope of the parent expression. The following arguments ``...`` specify an evaluation range, set or point. Their interpretation depends on the parent operator. The following cases are possible. Case 1: ``For(x, S)`` specifies iteration or comprehension for ``x`` ranging over the values of the set ``S``. This interpretation is used in operators that aggregate values over a set. The ``For`` expression may be followed by a filter predicate ``P(x)`` restricting the range to a subset of ``S``. Examples: ``Set(f(x), For(x, S))`` denotes `\{f(x) : x \in S\}`. ``Set(f(x), For(x, S), P(x))`` denotes `\{f(x) : x \in S \operatorname{and} P(x)\}`. ``Sum(f(x), For(x, S))`` denotes `\sum_{x \in S} f(x)`. ``Sum(f(x), For(x, S), P(x))`` denotes `\sum_{x \in S, \, P(x)} f(x)`. Case 2: ``For(x, a, b)`` specifies that ``x`` ranges between the endpoints ``a`` and ``b`` in the context of ``Sum``, ``Product``, ``Integral``, and similar operators. Examples: ``Sum(f(n), For(n, a, b))`` denotes `\sum_{n=a}^b f(n)`. The iteration is empty if `b < a`. ``Integral(f(x), For(x, a, b))`` denotes `\int_a^b f(x) dx`, where the integral follows a straight-line path from *a* to *b*. Swapping *a* and *b* negates the value. Case 3: ``For(x, a)`` specifies that ``x`` approaches the point ``a`` in the context of ``Limit``-type operator, or differentiation with respect to ``x`` at the point ``a`` in the context of a ``Derivative``-type operator. Examples: ``Derivative(f(x), For(x, a))`` denotes `f'(a)`. ``Limit(f(x), For(x, a))`` denotes `\lim_{x \to a} f(x)`. Case 4: ``For(x, a, n)`` specifies differentiation with respect to ``x`` at the point ``a`` to order ``n`` in the context of a ``Derivative``-type operator. Examples: ``Derivative(f(x), For(x, a, n))`` denotes `f^{(n)}(a)`. .. macro:: Where ``Where(f(x), Def(x, a))`` defines the symbol ``x`` as an alias for the expression ``a`` and evaluates the expression ``f(x)`` with this bound value of ``x``. This is equivalent to ``f(a)``. This may be rendered as `f(x) \; \operatorname{where} x = a`. ``Where(f(x), Def(f(t), a))`` defines the symbol ``f`` as a function mapping the dummy variable ``t`` to ``a``. ``Where(Add(a, b), Def(Tuple(a, b), T))`` is a destructuring assignment. .. macro:: Def Definition expression. This is a syntactical construct which does not represent a mathematical object on its own. The ``Def`` expression is used only within a ``Where``-expression; see that documentation of that symbol for more examples. ``Def(x, a)`` defines the symbol ``x`` as an alias for the expression ``a``. ``Def(f(x, y, z), a)`` defines the symbol ``f`` as a function of three variables. The dummy variables ``x``, ``y`` and ``z`` may appear within the expression ``a``. .. macro:: Fun ``Fun(x, expr)`` defines an anonymous univariate function mapping the symbol ``x`` to the expression ``expr``. The symbol ``x`` becomes locally bound within this ``Fun`` expression. .. macro:: Step .. macro:: Repeat Booleans and logic ------------------------------------------------------------------------ .. macro:: Equal ``Equal(a, b)``, signifying `a = b`, is ``True`` if ``a`` and ``b`` represent the same object, and ``False`` otherwise. This operator can be called with any number of arguments, in which case it evaluates whether all arguments are equal. .. macro:: NotEqual ``NotEqual(a, b)``, signifying `a \ne b`, is equivalent to ``Not(Equal(a, b))``. .. macro:: Same ``Same(a, b)`` gives ``a`` (or equivalently ``b``) if ``a`` and ``b`` represent the same object, and ``Undefined`` otherwise. This can be used to assert or emphasize that two expressions represent the same value within a formula. This operator can be called with any number of arguments, in which case it asserts that all arguments are equal. .. macro:: True ``True`` is a logical constant. .. macro:: False ``False`` is a logical constant. .. macro:: Not ``Not(x)`` is the logical negation of ``x``. .. macro:: And ``And(x, y)`` is the logical AND of ``x`` and ``y``. This function can be called with any number of arguments. .. macro:: Or ``Or(x, y)`` is the logical OR of ``x`` and ``y``. This function can be called with any number of arguments. .. macro:: Equivalent ``Equivalent(x, y)`` denotes the logical equivalence `x \Leftrightarrow y`. Semantically, this is the same as ``Equal`` called with logical arguments. .. macro:: Implies ``Implies(x, y)`` denotes the logical implication `x \implies y`. .. macro:: Exists Existence quantifier. ``Exists(f(x), For(x, S))`` denotes `f(x) \;\text{ for some } x \in S`. ``Exists(f(x), For(x, S), P(x))`` denotes `f(x) \;\text{ for some } x \in S \text{ with } P(x)`. .. macro:: All Universal quantifier. ``All(f(x), For(x, S))`` denotes `f(x) \;\text{ for all } x \in S`. ``All(f(x), For(x, S), P(x))`` denotes `f(x) \;\text{ for all } x \in S \text{ with } P(x)`. .. macro:: Cases ``Cases(Case(f(x), P(x)), Case(g(x), Otherwise))`` denotes: .. math :: \begin{cases} f(x), & P(x)\\g(x), & \text{otherwise}\\ \end{cases} ``Cases(Case(f(x), P(x)), Case(g(x), Q(x)), Case(h(x), Otherwise))`` denotes: .. math :: \begin{cases} f(x), & P(x)\\g(x), & Q(x)\\h(x), & \text{otherwise}\\ \end{cases} If both `P(x)` and `Q(x)` are true simultaneously, no ordering is implied; it is assumed that `f(x)` and `g(x)` give the same value for any such `x`. More generally, this operator can be called with any number of case distinctions. If the *Otherwise* case is omitted, the result is undefined if neither predicate is true. .. macro:: Case See ``Cases``. .. macro:: Otherwise See ``Cases``. Tuples, lists and sets ------------------------------------------------------------------------ .. macro:: Tuple .. macro:: List .. macro:: Set .. macro:: Item .. macro:: Element .. macro:: NotElement .. macro:: EqualAndElement .. macro:: Length .. macro:: Cardinality .. macro:: Concatenation .. macro:: Union .. macro:: Intersection .. macro:: SetMinus .. macro:: Subset .. macro:: SubsetEqual .. macro:: CartesianProduct .. macro:: CartesianPower .. macro:: Subsets ``Subsets(S)`` is the power set `\mathscr{P}(S)` comprising all subsets of the set ``S``. .. macro:: Sets ``Sets`` is the class `\operatorname{Sets}` of all sets. .. macro:: Tuples ``Tuples`` is the class of all tuples. ``Tuples(S)`` is the set of all tuples with elements in the set ``S``. ``Tuples(S, n)`` is the set of all length-``n`` tuples with elements in the set ``S``. Numbers and arithmetic ------------------------------------------------------------------------ Undefined ........................................................................ .. macro:: Undefined ``Undefined`` is the special value `\mathfrak{u}` (undefined). Particular numbers ........................................................................ .. macro:: Pi ``Pi`` is the constant `\pi`. .. macro:: NumberI ``NumberI`` is the imaginary unit `i`. The verbose name leaves ``i`` and ``I`` to be used as a variable names. .. macro:: NumberE ``NumberE`` is the base of the natural logarithm `e`. The verbose name leaves ``e`` and ``E`` to be used as a variable names. .. macro:: GoldenRatio ``GoldenRatio`` is the golden ratio `\varphi`. .. macro:: Euler ``Euler`` is Euler's constant `\gamma`. .. macro:: CatalanConstant ``CatalanConstant`` is Catalan's constant `G`. .. macro:: KhinchinConstant ``KhinchinConstant`` is Khinchin's constant `K`. .. macro:: GlaisherConstant ``GlaisherConstant`` is Glaisher's constant `A`. .. macro:: RootOfUnity ``RootOfUnity(n)`` is the principal complex *n*-th root of unity `\zeta_n = e^{2 \pi i / n}`. ``RootOfUnity(n, k)`` is the complex *n*-th root of unity `\zeta_n^k`. Number constructors ........................................................................ Remark: the rational number with numerator *p* and denominator *q* can be constructed as ``Div(p, q)``. .. macro:: Decimal ``Decimal(str)`` gives the rational number specified by the string *str* in ordinary decimal floating-point notation (for example ``-3.25e-725``). .. macro:: AlgebraicNumberSerialized .. macro:: PolynomialRootIndexed .. macro:: PolynomialRootNearest .. macro:: Enclosure .. macro:: Approximation .. macro:: Guess .. macro:: Unknown Arithmetic operations ........................................................................ .. macro:: Pos .. macro:: Neg .. macro:: Add .. macro:: Sub .. macro:: Mul .. macro:: Div .. macro:: Pow .. macro:: Sqrt .. macro:: Root Inequalities ........................................................................ .. macro:: Less .. macro:: LessEqual .. macro:: Greater .. macro:: GreaterEqual .. macro:: EqualNearestDecimal Sets of numbers ........................................................................ .. macro:: NN ``NN`` is the set of natural numbers (including 0), `\mathbb{N}`. .. macro:: ZZ ``ZZ`` is the set of integers, `\mathbb{Z}`. .. macro:: QQ ``QQ`` is the set of rational numbers, `\mathbb{Q}`. .. macro:: RR ``RR`` is the set of real numbers, `\mathbb{R}`. .. macro:: CC ``CC`` is the set of complex numbers, `\mathbb{C}`. .. macro:: Primes ``Primes`` is the set of positive prime numbers, `\mathbb{P}` .. macro:: IntegersGreaterEqual ``IntegersGreaterEqual(x)``, given an extended real number *x*, gives the set `\mathbb{Z}_{\ge x}` of integers greater than or equal to *x*. .. macro:: IntegersLessEqual ``IntegersLessEqual(x)``, given an extended real number *x*, gives the set `\mathbb{Z}_{\le x}` of integers less than or equal to *x*. .. macro:: Range ``Range(a, b)``, given integers *a* and *b*, gives the set `\{a, a+1, \ldots, b\}` of integers between *a* and *b*. This is the empty set if *a* is greater than *b*. .. macro:: AlgebraicNumbers The set of complex algebraic numbers `\overline{\mathbb{Q}}`. .. macro:: RealAlgebraicNumbers The set of real algebraic numbers `\overline{\mathbb{Q}}_{\mathbb{R}}`. .. macro:: Interval ``Interval(a, b)``, given extended real numbers *a* and *b*, gives the closed interval `[a, b]`. .. macro:: OpenInterval ``OpenInterval(a, b)``, given extended real numbers *a* and *b*, gives the open interval `(a, b)`. .. macro:: ClosedOpenInterval ``ClosedOpenInterval(a, b)``, given extended real numbers *a* and *b*, gives the closed-open interval `[a, b)`. .. macro:: OpenClosedInterval ``OpenClosedInterval(a, b)``, given extended real numbers *a* and *b*, gives the closed-open interval `(a, b]`. .. macro:: RealBall ``RealBall(m, r)``, given a real number *m* and an extended real number *r*, gives the the closed real ball `[m \pm r]` with center *m* and radius *r*. .. macro:: OpenRealBall ``OpenRealBall(m, r)``, given a real number *m* and an extended real number *r*, gives the the open real ball `(m \pm r)` with center *m* and radius *r*. .. macro:: OpenComplexDisk ``OpenComplexDisk(m, r)``, given a complex number *m* and an extended real number *r*, gives the open complex disk `D(m, r)` with center *m* and radius *r*. .. macro:: ClosedComplexDisk ``ClosedComplexDisk(m, r)``, given a complex number *m* and a real number *r*, gives the closed complex disk `\overline{D}(m, r)` with center *m* and radius *r*. .. macro:: UpperHalfPlane ``UpperHalfPlane`` is the set `\mathbb{H}` of complex numbers with positive imaginary part. .. macro:: UnitCircle .. macro:: BernsteinEllipse .. macro:: Lattice Infinities and extended numbers ........................................................................ .. macro:: Infinity ``Infinity`` is the positive signed infinity `\infty`. .. macro:: UnsignedInfinity ``UnsignedInfinity`` is the unsigned infinity `\tilde \infty`. .. macro:: RealSignedInfinities ``RealSignedInfinities`` is the set of real signed infinities `\{+\infty, -\infty\}`. .. macro:: ComplexSignedInfinities ``ComplexSignedInfinities`` is the set of complex signed infinities `\{e^{i \theta} \cdot \infty : \theta \in \mathbb{R}\}`. .. macro:: RealInfinities ``RealInfinities`` is the set of real infinities (signed and unsigned) `\{+\infty, -\infty\} \cup \{\tilde \infty\}`. .. macro:: ComplexInfinities ``ComplexInfinities`` is the set of complex infinities (signed and unsigned) `\{e^{i \theta} \cdot \infty : \theta \in \mathbb{R}\} \cup \{\tilde \infty\}`. .. macro:: ExtendedRealNumbers ``ExtendedRealNumbers`` is the set of extended real numbers `\mathbb{R} \cup \{+\infty, -\infty\}`. .. macro:: ProjectiveRealNumbers ``ProjectiveRealNumbers`` is the set of projectively extended real numbers `\mathbb{R} \cup \{\tilde \infty\}`. .. macro:: SignExtendedComplexNumbers ``SignExtendedComplexNumbers`` is the set of complex numbers extended with signed infinities `\mathbb{C} \cup \{e^{i \theta} \cdot \infty : \theta \in \mathbb{R}\}`. .. macro:: ProjectiveComplexNumbers ``ProjectiveComplexNumbers`` is the set of projectively extended complex numbers (also known as the Riemann sphere) `\mathbb{C} \cup \{\tilde \infty\}`. .. macro:: RealSingularityClosure ``RealSingularityClosure`` is the Calcium singularity closure for real functions, encompassing real numbers, signed infinities, unsigned infinity, and *undefined* (u). This set is defined as `\mathbb{R}_{\text{Sing}} = \mathbb{R} \cup \{+\infty, -\infty\} \cup \{\tilde \infty\} \cup \{ \mathfrak{u} \}`. .. macro:: ComplexSingularityClosure ``ComplexSingularityClosure`` is the Calcium singularity closure for complex functions, encompassing complex numbers, signed infinities, unsigned infinity, and *undefined* (u). This set is defined as `\mathbb{C}_{\text{Sing}} = \mathbb{C} \cup \{e^{i \theta} \cdot \infty : \theta \in \mathbb{R}\} \cup \{\tilde \infty\} \cup \{ \mathfrak{u} \}`. Operators and calculus ------------------------------------------------------------------------ Sums and products ........................................................................ .. macro:: Sum .. macro:: Product .. macro:: PrimeSum .. macro:: PrimeProduct .. macro:: DivisorSum .. macro:: DivisorProduct Solutions and zeros ........................................................................ .. macro:: Zeros .. macro:: UniqueZero .. macro:: Solutions .. macro:: UniqueSolution Extreme values ........................................................................ .. macro:: Supremum .. macro:: Infimum .. macro:: Minimum .. macro:: Maximum .. macro:: ArgMin .. macro:: ArgMax .. macro:: ArgMinUnique .. macro:: ArgMaxUnique Limits ........................................................................ .. macro:: Limit .. macro:: SequenceLimit .. macro:: RealLimit .. macro:: LeftLimit .. macro:: RightLimit .. macro:: ComplexLimit .. macro:: MeromorphicLimit .. macro:: SequenceLimitInferior .. macro:: SequenceLimitSuperior .. macro:: AsymptoticTo Derivatives ........................................................................ .. macro:: Derivative .. macro:: RealDerivative .. macro:: ComplexDerivative .. macro:: ComplexBranchDerivative .. macro:: MeromorphicDerivative Integrals ........................................................................ .. macro:: Integral Complex analysis ........................................................................ .. macro:: Path .. macro:: CurvePath .. macro:: Poles .. macro:: IsHolomorphicOn .. macro:: IsMeromorphicOn .. macro:: Residue .. macro:: ComplexZeroMultiplicity .. macro:: AnalyticContinuation Matrices and linear algebra ------------------------------------------------------------------------ .. macro:: Matrix .. macro:: Row .. macro:: Column .. macro:: RowMatrix .. macro:: ColumnMatrix .. macro:: DiagonalMatrix .. macro:: Matrix2x2 .. macro:: ZeroMatrix .. macro:: IdentityMatrix .. macro:: Det .. macro:: Spectrum .. macro:: SingularValues .. macro:: Matrices .. macro:: SL2Z .. macro:: PSL2Z .. macro:: SpecialLinearGroup .. macro:: GeneralLinearGroup .. macro:: HilbertMatrix Polynomials, series and rings ------------------------------------------------------------------------ .. macro:: Pol .. macro:: Ser .. macro:: Polynomial .. macro:: Coefficient .. macro:: PolynomialDegree .. macro:: Polynomials .. macro:: PolynomialFractions .. macro:: FormalPowerSeries .. macro:: FormalLaurentSeries .. macro:: FormalPuiseuxSeries .. macro:: Zero .. macro:: One .. macro:: Characteristic .. macro:: Rings .. macro:: CommutativeRings .. macro:: Fields .. macro:: QuotientRing .. macro:: FiniteField .. macro:: EqualQSeriesEllipsis .. macro:: IndefiniteIntegralEqual .. macro:: QSeriesCoefficient .. macro:: Call .. macro:: CallIndeterminate Special functions ------------------------------------------------------------------------ Number parts and step functions ........................................................................ .. macro:: Abs .. macro:: Sign .. macro:: Re .. macro:: Im .. macro:: Arg .. macro:: Conjugate .. macro:: Csgn .. macro:: RealAbs .. macro:: Max .. macro:: Min .. macro:: Floor .. macro:: Ceil .. macro:: KroneckerDelta Primes and divisibility ........................................................................ .. macro:: IsOdd .. macro:: IsEven .. macro:: CongruentMod .. macro:: Divides .. macro:: Mod .. macro:: GCD .. macro:: LCM .. macro:: XGCD .. macro:: IsPrime .. macro:: Prime .. macro:: PrimePi .. macro:: DivisorSigma .. macro:: MoebiusMu .. macro:: EulerPhi .. macro:: DiscreteLog .. macro:: LegendreSymbol .. macro:: JacobiSymbol .. macro:: KroneckerSymbol .. macro:: SquaresR .. macro:: LiouvilleLambda Elementary functions ........................................................................ .. macro:: Exp .. macro:: Log .. macro:: Sin .. macro:: Cos .. macro:: Tan .. macro:: Cot .. macro:: Sec .. macro:: Csc .. macro:: Sinh .. macro:: Cosh .. macro:: Tanh .. macro:: Coth .. macro:: Sech .. macro:: Csch .. macro:: Asin .. macro:: Acos .. macro:: Atan .. macro:: Acot .. macro:: Asec .. macro:: Acsc .. macro:: Asinh .. macro:: Acosh .. macro:: Atanh .. macro:: Acoth .. macro:: Asech .. macro:: Acsch .. macro:: Atan2 .. macro:: Sinc .. macro:: LambertW Combinatorial functions ........................................................................ .. macro:: SloaneA .. macro:: SymmetricPolynomial .. macro:: Cyclotomic .. macro:: Fibonacci .. macro:: BernoulliB .. macro:: BernoulliPolynomial .. macro:: StirlingCycle .. macro:: StirlingS1 .. macro:: StirlingS2 .. macro:: EulerE .. macro:: EulerPolynomial .. macro:: BellNumber .. macro:: PartitionsP .. macro:: LandauG Gamma function and factorials ........................................................................ .. macro:: Factorial .. macro:: Binomial .. macro:: Gamma .. macro:: LogGamma .. macro:: DoubleFactorial .. macro:: RisingFactorial .. macro:: FallingFactorial .. macro:: HarmonicNumber .. macro:: DigammaFunction .. macro:: DigammaFunctionZero .. macro:: BetaFunction .. macro:: BarnesG .. macro:: LogBarnesG .. macro:: StirlingSeriesRemainder .. macro:: LogBarnesGRemainder Orthogonal polynomials ........................................................................ .. macro:: ChebyshevT .. macro:: ChebyshevU .. macro:: LegendreP .. macro:: JacobiP .. macro:: HermiteH .. macro:: LaguerreL .. macro:: GegenbauerC .. macro:: SphericalHarmonicY .. macro:: LegendrePolynomialZero .. macro:: GaussLegendreWeight Exponential integrals ........................................................................ .. macro:: Erf .. macro:: Erfc .. macro:: Erfi .. macro:: UpperGamma .. macro:: LowerGamma .. macro:: IncompleteBeta .. macro:: IncompleteBetaRegularized .. macro:: LogIntegral .. macro:: ExpIntegralE .. macro:: ExpIntegralEi .. macro:: SinIntegral .. macro:: SinhIntegral .. macro:: CosIntegral .. macro:: CoshIntegral .. macro:: FresnelC .. macro:: FresnelS Bessel and Airy functions ........................................................................ .. macro:: AiryAi .. macro:: AiryBi .. macro:: AiryAiZero .. macro:: AiryBiZero .. macro:: BesselJ .. macro:: BesselI .. macro:: BesselY .. macro:: BesselK .. macro:: HankelH1 .. macro:: HankelH2 .. macro:: BesselJZero .. macro:: BesselYZero .. macro:: CoulombF .. macro:: CoulombG .. macro:: CoulombH .. macro:: CoulombC .. macro:: CoulombSigma Hypergeometric functions ........................................................................ .. macro:: Hypergeometric0F1 .. macro:: Hypergeometric1F1 .. macro:: Hypergeometric1F2 .. macro:: Hypergeometric2F1 .. macro:: Hypergeometric2F2 .. macro:: Hypergeometric2F0 .. macro:: Hypergeometric3F2 .. macro:: HypergeometricU .. macro:: HypergeometricUStar .. macro:: HypergeometricUStarRemainder .. macro:: Hypergeometric0F1Regularized .. macro:: Hypergeometric1F1Regularized .. macro:: Hypergeometric1F2Regularized .. macro:: Hypergeometric2F1Regularized .. macro:: Hypergeometric2F2Regularized .. macro:: Hypergeometric3F2Regularized Zeta and L-functions ........................................................................ .. macro:: RiemannZeta .. macro:: RiemannZetaZero .. macro:: RiemannHypothesis .. macro:: RiemannXi .. macro:: HurwitzZeta .. macro:: LerchPhi .. macro:: PolyLog .. macro:: MultiZetaValue .. macro:: DirichletL .. macro:: DirichletLZero .. macro:: DirichletLambda .. macro:: DirichletCharacter .. macro:: DirichletGroup .. macro:: PrimitiveDirichletCharacters .. macro:: GeneralizedRiemannHypothesis .. macro:: ConreyGenerator .. macro:: GeneralizedBernoulliB .. macro:: StieltjesGamma .. macro:: KeiperLiLambda .. macro:: GaussSum Elliptic integrals ........................................................................ .. macro:: AGM .. macro:: AGMSequence .. macro:: EllipticK .. macro:: EllipticE .. macro:: EllipticPi .. macro:: IncompleteEllipticF .. macro:: IncompleteEllipticE .. macro:: IncompleteEllipticPi .. macro:: CarlsonRF .. macro:: CarlsonRG .. macro:: CarlsonRJ .. macro:: CarlsonRD .. macro:: CarlsonRC .. macro:: CarlsonHypergeometricR .. macro:: CarlsonHypergeometricT Elliptic, theta and modular functions ........................................................................ .. macro:: JacobiTheta .. macro:: JacobiThetaQ .. macro:: DedekindEta .. macro:: ModularJ .. macro:: ModularLambda .. macro:: EisensteinG .. macro:: EisensteinE .. macro:: DedekindSum .. macro:: WeierstrassP .. macro:: WeierstrassZeta .. macro:: WeierstrassSigma .. macro:: EllipticRootE .. macro:: HilbertClassPolynomial .. macro:: EulerQSeries .. macro:: DedekindEtaEpsilon .. macro:: ModularGroupAction .. macro:: ModularGroupFundamentalDomain .. macro:: ModularLambdaFundamentalDomain .. macro:: PrimitiveReducedPositiveIntegralBinaryQuadraticForms .. macro:: JacobiThetaEpsilon .. macro:: JacobiThetaPermutation Nonsemantic markup ........................................................................ .. macro:: Ellipsis ``Ellipsis`` renders as `\ldots` in LaTeX. It can be used to indicate missing function arguments for display purposes, but it has no predefined builtin semantics. .. macro:: Parentheses ``Parentheses(x)`` semantically represents ``x``, but renders with parentheses (`\left(x\right)`) when converted to LaTeX. .. macro:: Brackets ``Brackets(x)`` semantically represents ``x``, but renders with brackets (`\left[x\right]`) when converted to LaTeX. .. macro:: Braces ``Braces(x)`` semantically represents ``x``, but renders with braces (`\left\{x\right\}`) when converted to LaTeX. .. macro:: AngleBrackets ``AngleBrackets(x)`` semantically represents ``x``, but renders with angle brackets (`\left\langle x\right\rangle`) when converted to LaTeX. .. macro:: Logic ``Logic(x)`` semantically represents ``x``, but forces logical expressions within *x* to be rendered using symbols instead of text. .. macro:: ShowExpandedNormalForm ``ShowExpandedNormalForm(x)`` semantically represents ``x``, but displays the expanded normal form of the expression instead of rendering the expression verbatim. Warning: this triggers a nontrivial (potentially very expensive) computation. .. macro:: Subscript .. raw:: latex \newpage calcium-0.4.1/doc/source/fmpz_mpoly_q.rst000066400000000000000000000213111407704557200204550ustar00rootroot00000000000000.. _fmpz-mpoly-q: **fmpz_mpoly_q.h** -- multivariate rational functions over Q =============================================================================== An :type:`fmpz_mpoly_q_t` represents an element of `\mathbb{Q}(x_1,\ldots,x_n)` for fixed *n* as a pair of Flint multivariate polynomials (:type:`fmpz_mpoly_t`). Instances are always kept in canonical form by ensuring that the GCD of numerator and denominator is 1 and that the coefficient of the leading term of the denominator is positive. The user must create a multivariate polynomial context (:type:`fmpz_mpoly_ctx_t`) specifying the number of variables *n* and the monomial ordering. Types and macros ------------------------------------------------------------------------------- .. type:: fmpz_mpoly_q_struct .. type:: fmpz_mpoly_q_t An *fmpz_mpoly_q_struct* consists of a pair of *fmpz_mpoly_struct*:s. An *fmpz_mpoly_q_t* is defined as an array of length one of type *fmpz_mpoly_q_struct*, permitting an *fmpz_mpoly_q_t* to be passed by reference. .. macro:: fmpz_mpoly_q_numref(x) Macro returning a pointer to the numerator of *x* which can be used as an *fmpz_mpoly_t*. .. macro:: fmpz_mpoly_q_denref(x) Macro returning a pointer to the denominator of *x* which can be used as an *fmpz_mpoly_t*. Memory management ------------------------------------------------------------------------------- .. function:: void fmpz_mpoly_q_init(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) Initializes *res* for use, and sets its value to zero. .. function:: void fmpz_mpoly_q_clear(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) Clears *res*, freeing or recycling its allocated memory. Assignment ------------------------------------------------------------------------------- .. function:: void fmpz_mpoly_q_swap(fmpz_mpoly_q_t x, fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) Swaps the values of *x* and *y* efficiently. .. function:: void fmpz_mpoly_q_set(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_set_fmpq(fmpz_mpoly_q_t res, const fmpq_t x, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_set_fmpz(fmpz_mpoly_q_t res, const fmpz_t x, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_set_si(fmpz_mpoly_q_t res, slong x, const fmpz_mpoly_ctx_t ctx) Sets *res* to the value *x*. Canonicalisation ------------------------------------------------------------------------------- .. function:: void fmpz_mpoly_q_canonicalise(fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) Puts the numerator and denominator of *x* in canonical form by removing common content and making the leading term of the denominator positive. .. function:: int fmpz_mpoly_q_is_canonical(const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) Returns whether *x* is in canonical form. In addition to verifying that the numerator and denominator have no common content and that the leading term of the denominator is positive, this function checks that the denominator is nonzero and that the numerator and denominator have correctly sorted terms (these properties should normally hold; verifying them provides an extra consistency check for test code). Properties ------------------------------------------------------------------------------- .. function:: int fmpz_mpoly_q_is_zero(const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) Returns whether *x* is the constant 0. .. function:: int fmpz_mpoly_q_is_one(const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) Returns whether *x* is the constant 1. .. function:: void fmpz_mpoly_q_used_vars(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_used_vars_num(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_used_vars_den(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx) For each variable, sets the corresponding entry in *used* to the boolean flag indicating whether that variable appears in the rational function (respectively its numerator or denominator). Special values ------------------------------------------------------------------------------- .. function:: void fmpz_mpoly_q_zero(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) Sets *res* to the constant 0. .. function:: void fmpz_mpoly_q_one(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) Sets *res* to the constant 1. .. function:: void fmpz_mpoly_q_gen(fmpz_mpoly_q_t res, slong i, const fmpz_mpoly_ctx_t ctx) Sets *res* to the generator `x_{i+1}`. Requires `0 \le i < n` where *n* is the number of variables of *ctx*. Input and output ------------------------------------------------------------------------------- .. function:: void fmpz_mpoly_q_print_pretty(const fmpz_mpoly_q_t f, const char ** x, fmpz_mpoly_ctx_t ctx) Prints *res* to standard output. If *x* is not *NULL*, the strings in *x* are used as the symbols for the variables. Random generation ------------------------------------------------------------------------------- .. function:: void fmpz_mpoly_q_randtest(fmpz_mpoly_q_t res, flint_rand_t state, slong length, mp_limb_t coeff_bits, slong exp_bound, const fmpz_mpoly_ctx_t ctx) Sets *res* to a random rational function where both numerator and denominator have up to *length* terms, coefficients up to size *coeff_bits*, and exponents strictly smaller than *exp_bound*. Comparisons ------------------------------------------------------------------------------- .. function:: int fmpz_mpoly_q_equal(const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) Returns whether *x* and *y* are equal. Arithmetic ------------------------------------------------------------------------------- .. function:: void fmpz_mpoly_q_neg(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) Sets *res* to the negation of *x*. .. function:: void fmpz_mpoly_q_add(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_add_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_add_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_add_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong y, const fmpz_mpoly_ctx_t ctx) Sets *res* to the sum of *x* and *y*. .. function:: void fmpz_mpoly_q_sub(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_sub_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_sub_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_sub_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong y, const fmpz_mpoly_ctx_t ctx) Sets *res* to the difference of *x* and *y*. .. function:: void fmpz_mpoly_q_mul(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_mul_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_mul_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong y, const fmpz_mpoly_ctx_t ctx) Sets *res* to the product of *x* and *y*. .. function:: void fmpz_mpoly_q_div(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_div_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_div_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_div_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong y, const fmpz_mpoly_ctx_t ctx) Sets *res* to the quotient of *x* and *y*. Division by zero calls *flint_abort*. .. function:: void fmpz_mpoly_q_inv(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) Sets *res* to the inverse of *x*. Division by zero calls *flint_abort*. Content ------------------------------------------------------------------------------- .. function:: void _fmpz_mpoly_q_content(fmpz_t num, fmpz_t den, const fmpz_mpoly_t xnum, const fmpz_mpoly_t xden, const fmpz_mpoly_ctx_t ctx) void fmpz_mpoly_q_content(fmpq_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) Sets *res* to the content of the coefficients of *x*. .. raw:: latex \newpage calcium-0.4.1/doc/source/history.rst000066400000000000000000000224241407704557200174500ustar00rootroot00000000000000.. _history: History and changes =============================================================================== For more details, view the commit log in the git repository https://github.com/fredrik-johansson/calcium Old releases of the code can be accessed from https://github.com/fredrik-johansson/calcium/releases 2021-07-24 - version 0.4.1 ------------------------------------------------------------------------------- * Flint 2.8 compatibility. 2021-05-28 - version 0.4 ------------------------------------------------------------------------------- * Algebraic numbers * Fixed bug in special-casing of roots of unity in qqbar_root_ui. * Fixed qqbar_randtest with bits == 1. * Faster qqbar_cmp_re for nearby reals. * Faster qqbar polynomial evaluation and powering using linear algebra. * Improved qqbar_abs, qqbar_abs2 to produce cleaner enclosures. * Use a slightly better method to detect real numbers in qqbar_sgn_im. * Added qqbar_hash. * Added qqbar_get_fmpq, qqbar_get_fmpz. * Added qqbar_pow_fmpq, qqbar_pow_fmpz, qqbar_pow_si. * Added qqbar_numerator, qqbar_denominator. * Basic arithmetic and elementary functions * Improved ca_condense_field: automatically demote to a simple number field when the only used extension number is algebraic. * Improved multivariate field arithmetic to automatically remove algebraic or redundant monomial factors from denominators. * Added ca_pow_si_arithmetic (guaranteed in-field exponentiation). * Added polynomial evaluation functions (ca_fmpz_poly_evaluate, ca_fmpq_poly_evaluate, ca_fmpz_poly_evaluate, ca_fmpz_mpoly_q_evaluate). * Added several helper functions (ca_is_special, ca_is_qq_elem, ca_is_qq_elem_zero, ca_is_qq_elem_one, ca_is_qq_elem_integer, ca_is_nf_elem, ca_is_cyclotomic_nf_elem, ca_is_generic_elem). * Added ca_rewrite_complex_normal_form. * Perform direct complex conjugation in cyclotomic fields. * Use ca_get_acb_raw instead of ca_get_acb when printing to avoid expensive recomputations. * Added alternative algorithms for various basic functions. * Deep complex conjugation. * Use complex conjugation in is_real, is_imaginary, is_negative_real. * Added functions for unsafe inversion for internal use. * Significantly stronger zero testing in mixed algebraic-transcendental fields. * Added ca_arg. * Added special case for testing equality between number field elements and rationals. * Added ca_sin_cos, ca_sin, ca_cos, ca_tan and variants. * Added ca_atan, ca_asin, ca_acos and variants. * Added ca_csgn. * Improved ca_get_acb and ca_get_acb_accurate_parts to fall back on exact zero tests when direct numerical evaluation does not give precise enclosures. * Added ca_get_decimal_str. * More automatic simplifications of logarithms (simplify logarithms of exponentials, square roots and powers raised to integer powers). * More automatic simplifications of square roots (simplify square roots of exponentials, square roots and powers raised to integer powers). * Improved order comparisons (ca_check_ge etc.) to handle special values and to fall back on strong equality tests. * Fixed a test failure in the ca_mat module. * Polynomials * Added ca_poly_inv_series, ca_poly_div_series (power series division). * Added ca_poly_exp_series (power series exponential). * Added ca_poly_log_series (power series logarithm). * Added ca_poly_atan_series (power series arctangent). * Other * Added fmpz_mpoly_q_used_vars. * Remove useless rpath line from configure (reported by Julien Puydt). * Added missing declaration of fexpr_hash. * Fixed crashes on OS X in Python interface (contributed by deinst). * Fixed memory leaks in Python string conversions (contributed by deinst). * Reserve I, E for symbolic expressions in Python interface. 2021-04-23 - version 0.3 ------------------------------------------------------------------------------- * Symbolic expressions * Added the fexpr module for flat-packed unevaluated symbolic expressions. * LaTeX output. * Basic manipulation (construction, replacement, accessing subexpressions). * Numerical evaluation with Arb. * Expanded normal form. * Conversion methods for other types. * Enable LaTeX rendering of objects in Jupyter notebooks. * Algebraic numbers * Fix a major performance issue (slow root refinement) that made Calcium as a whole far slower than necessary. * Added qqbar_cmp_root_order; sort polynomial roots consistently by default. * Added qqbar_get_quadratic. * Added qqbar_equal_fmpq_poly_val and use it to speed up checking guessed values. * Conversion of qqbar_t to and from symbolic expression (qqbar_set_fexpr, qqbar_get_fexpr_repr, qqbar_get_fexpr_root_nearest, qqbar_get_fexpr_root_indexed, qqbar_get_fexpr_formula). * Fixed bugs in qqbar_cmpabs_re, cmpabs_im. * Optimized qqbar_cmp_im and qqbar_cmpabs_im for conjugates with mirror symmetry. * Added qqbar_pow (taking a qqbar exponent). * Special-case roots of unity in qqbar_pow_ui, qqbar_root_ui, qqbar_abs and qqbar_abs2. * Wrapped qqbar in Python. * Polynomials * Added several utility functions. * Optimized polynomial multiplication with rational entries. * Fast polynomial multiplication over number fields. * Matrices * Fast matrix multiplication over number fields. * Right kernel (ca_mat_right_kernel). * Matrix diagonalization (ca_mat_diagonalization). * Jordan normal form (ca_mat_jordan_form, ca_mat_jordan_transformation, ca_mat_jordan_blocks). * Matrix exponential (ca_mat_exp). * Matrix logarithm (ca_mat_log). * Polynomial evaluation (ca_mat_ca_poly_evaluate). * Cofactor expansion algorithm for determinant and adjugate (ca_mat_adjugate_cofactor). * Added several utility functions. * Improved algorithm selection in ca_mat_inv. * Solving using the adjugate matrix. * Danilevsky characteristic polynomial algorithm (ca_mat_charpoly_danilevsky). * Field elements * Use factoring in ca_sqrt to enable more simplifications. * Simplify square roots and logarithms of negative real numbers. * Optimized ca_sub. * Conversion of ca_t to and from symbolic expressions (ca_set_fexpr, ca_get_fexpr). * Added function for assigning elements between context objects (ca_transfer). * Fixed a possible memory corruption bug when Vieta's formulas are used. * Optimized constructing square roots of rational numbers. * Other * Added demonstration notebook to documentation. * Fixed OSX compatibility in Python wrapper (contributed by deinst). * Fixed bug in calcium_write_acb. * Fixed bug in fmpz_mpoly_vec_set_primitive_unique (contributed by gbunting). 2020-10-16 - version 0.2 ------------------------------------------------------------------------------- * Basic arithmetic and expression simplification * Use Gröbner basis for reduction ideals, making simplification much more robust. * Compute all linear relations with LLL simultaneously instead of piecemeal. * Make monomial ordering configurable (default is lex as before). * Use Vieta's formulas to simplify expressions involving conjugate algebraic numbers. * Denest exponentials of symbolic logarithms. * Denest logarithms of symbolic powers and square roots. * Denest powers of symbolic powers. * Simplify exponentials that evaluate to roots of unity. * Simplify logarithms of roots of unity. * Improve ideal reduction to avoid some unnecessary GCD computations. * Python wrapper * Calcium now includes a minimal ctypes-based Python wrapper for testing. * New ca_mat module for matrices * Mostly using naive basecase algorithms. * Matrix arithmetic, basic manipulation. * Construction of special matrices (Hilbert, Pascal, Stirling, DFT). * LU factorization. * Fraction-free LU decomposition. * Nonsingular solving and inverse. * Reduced row echelon form. * Rank. * Trace and determinant. * Characteristic polynomial. * Computation of eigenvalues with multiplicities. * New ca_poly module for polynomials * Mostly using naive basecase algorithms. * Polynomial arithmetic, basic manipulation. * Polynomial division. * Evaluation and composition. * Derivative and integral. * GCD (Euclidean algorithm). * Squarefree factorization. * Computation of roots with multiplicities. * Construction from given roots. * New ca_vec module for vectors. * Memory management and basic scalar operations. * Bug fixes * Fix bug in powering number field elements. * Fix bug in qqbar_log_pi_i. * Fix aliasing bug in ca_pow. * New basic functions * Conversion from double: ca_set_d, ca_set_d_d. * Special functions: ca_erf, ca_erfi, ca_erfc, with algebraic relations. * Special functions: ca_gamma (incomplete simplification algorithms). * New utils_flint module for Flint utilities * Vectors of multivariate polynomials. * Construction of elementary symmetric polynomials. * Gröbner basis computation (naive Buchberger algorithm). * Documentation and presentation * Various improvements to the documentation. * DFT example program. 2020-09-08 - version 0.1 ------------------------------------------------------------------------------- * Initial test release. * ca module (exact real and complex numbers). * fmpz_mpoly_q module (multivariate rational functions over Q). * qqbar module (algebraic numbers represented by minimal polynomials). * Example programs. .. raw:: latex \newpage calcium-0.4.1/doc/source/index.rst000066400000000000000000000062321407704557200170550ustar00rootroot00000000000000Calcium =================================== .. only:: html .. image:: _static/ca2.svg :align: center **Calcium** (pronounced "kalkium") is a C library for exact computation with real and complex numbers. It is capable of rigorously deciding the truth of any constant relation involving algebraic numbers and many relations involving transcendental numbers, for example .. math :: \frac{\log(\sqrt{2}+\sqrt{3})}{\log(5+2\sqrt{6})} = \frac{1}{2}, \quad i^{\,i} = \exp\left(\frac{\pi}{ \left({\left(\sqrt{-2}\right)}^{\sqrt{2}}\right)^{\sqrt{2}}}\right), \quad 10^{-30} < \frac{640320^3 + 744}{e^{\pi \sqrt{163}}} - 1 < 10^{-29}. Calcium is free software (LGPL). It depends on `GMP `_, `MPFR `_, `Flint `_, `Antic `_ and `Arb `_. * Source code: https://github.com/fredrik-johansson/calcium * Bug reports and feature requests: https://github.com/fredrik-johansson/calcium/issues * Mailing list: `flint-devel `_ This documentation is available in HTML format at http://fredrikj.net/calcium/ and in PDF format at http://fredrikj.net/calcium/calcium.pdf. This edition of the documentation was updated |today| and describes Calcium |version|. Tutorial --------------------------- For new users, this introductory `Jupyter notebook `_ is a good place to start. General information --------------------------- .. toctree:: :maxdepth: 2 introduction.rst setup.rst examples.rst General modules ---------------------- .. toctree:: :maxdepth: 2 calcium.rst Numbers ---------------------- .. toctree:: :maxdepth: 2 ca.rst ca_vec.rst Matrices and polynomials ------------------------ .. toctree:: :maxdepth: 2 ca_poly.rst ca_mat.rst Field and extension number constructions ---------------------------------------- These modules are used internally by the :type:`ca_t` type to construct towers of algebraic and transcendental number fields. The user does not normally need to use these modules directly outside of advanced applications requiring inspection of the symbolic representations of numbers. .. toctree:: :maxdepth: 2 ca_ext.rst ca_field.rst Symbolic expressions -------------------------------------------- .. toctree:: :maxdepth: 2 fexpr.rst fexpr_builtin.rst Basic algebraic structures -------------------------------------------- The following modules implement useful exact structures independently of the :type:`ca_t` type. They are used internally in Calcium, but the interfaces are stable and use in appropriate external applications is encouraged. .. toctree:: :maxdepth: 2 fmpz_mpoly_q.rst qqbar.rst utils_flint.rst Python interface ---------------------- .. toctree:: :maxdepth: 1 pycalcium.rst Credits and references ---------------------- .. toctree:: :maxdepth: 2 bibliography.rst Version history ---------------------- .. toctree:: :maxdepth: 1 history.rst .. only:: html Indices and tables ---------------------- * :ref:`genindex` calcium-0.4.1/doc/source/introduction.rst000066400000000000000000000152251407704557200204710ustar00rootroot00000000000000.. _introduction: Introduction =============================================================================== Exact numbers in Calcium ----------------------------------------------------------------------- The core idea behind Calcium is to represent real and complex numbers as elements of extension fields .. math :: \mathbb{Q}(a_1, \ldots, a_n) of the rational numbers, where the extension numbers `a_k` are described by symbolic expressions (which may depend on other fields recursively). The system constructs such fields automatically as needed to represent the results of computations. Any extension field is isomorphic to a formal field .. math :: \mathbb{Q}(a_1,\ldots,a_n) \;\; \cong \;\; K_{\text{formal}} := \operatorname{Frac}(\mathbb{Q}[X_1,\ldots,X_n] / I) where *I* is the ideal of algebraic relations among the extension numbers. The relations may involve algebraic numbers (for example: `i^2 + 1 = 0`), transcendental numbers (for example: `e^{-\pi} \cdot e^{\pi} = 1`), or combinations thereof. Computation in the formal field depends (in general) on multivariate polynomial arithmetic together with use of a Gröbner basis for the ideal. The map from the formal field to the true complex field is maintained using arbitrary-precision ball arithmetic where necessary. As an important special case, Calcium can be used for arithmetic in algebraic number fields (embedded explicitly in `\mathbb{C}`) .. math :: \mathbb{Q}(a) \cong \mathbb{Q}[X] / \langle f(X) \rangle with excellent performance thanks to internal use of the Antic library. It will not always work perfectly: although Calcium by design should never give a mathematically erroneous answer, it may be unable to simplify a result as much as expected and it may be unable to decide a predicate (in which case it can return "Unknown"). Equality is at least decidable over the algebraic numbers `\overline{\mathbb{Q}}` (for practical degrees and bit sizes of the numbers!), and in certain cases involving transcendentals. We hope to improve Calcium's capabilities gradually through enhancements to its built-in algorithms and through customization options. Usage details ....................................................................... To understand how Calcium works more concretely, see :ref:`examples` and the documentation for the main Calcium number type (:type:`ca_t`): * :ref:`ca` Implementation details for extension numbers and formal fields can be found in the documentation of the corresponding modules: * :ref:`ca-ext` * :ref:`ca-field` The following modules are used internally for arithmetic in transcendental number fields (rational function fields) `\mathbb{Q}(x_1,\ldots,x_n)` and over the field of algebraic numbers `\overline{\mathbb{Q}}`, respectively. They may be of independent interest: * :ref:`fmpz-mpoly-q` * :ref:`qqbar` FAQ ----------------------------------------------------------------------- **Isn't x = 0 undecidable?** In general, yes: equality over the reals is undecidable. In practice, much of calculus and elementary number theory can be done with numbers that are simple algebraic combinations of well-known elementary and special functions, and there are heuristics that work quite well for deciding predicates about such numbers. Calcium will be able to give a definitive answer at least in simple cases (for example, proving `16 \operatorname{atan}(\tfrac{1}{5}) - 4 \operatorname{atan}(\tfrac{1}{239}) = \pi` or `\sqrt{5+2\sqrt{6}} = \sqrt{2}+\sqrt{3}`), and will simply answer "Unknown" when its heuristics are not powerful enough. **How does Calcium compare to ordinary numerical computing?** Calcium is far too slow to replace floating-point numbers for 99.93% of scientific computing. The target is symbolic and algebraic computation. Nevertheless, Calcium may well be useful as a tool to test and enhance the capabilities of numerical programs. **How does Calcium compare to Arb arithmetic?** The main advantage of Calcium over ball arithmetic alone is the ability to do exact comparisons. The automatic precision management in Calcium can also be convenient. Calcium will usually be slower than Arb arithmetic. If a computation is mostly numerical, it is probably better to try using Arb first, and fall back on an exact calculation with Calcium only if that fails because an exact comparison is needed. **How does Calcium compare to symbolic computation systems (Mathematica, SymPy, etc.)?** Calculating with constant values is only a small part of what such systems have to do, but it is one of the most complex parts. Existing computer algebra systems sometimes manage this very well, and sometimes fail horribly. The most common problems are 1) getting numerical error bounds or branch cuts wrong, and 2) slowing down too much when the expressions get large. Calcium is intended to address both problems (through rigorous numerical evaluation and use of fast polynomial arithmetic). Ultimately, Calcium will no doubt handle some problems better and others worse, and it should be considered a complement to existing computer algebra systems rather than a replacement. A symbolic expression simplifier may use Calcium evaluation as one of its tools, but this probably needs to be done selectively and in combination with many other heuristics. **Why is Calcium written in C?** The main advantage of developing Calcium as a C library is that it will not be tied to a particular programming language ecosystem: C is uniquely easy to interface from almost any other language. The second most important reason is familiarity: Calcium follows the design of Flint and Arb (coding style, naming, module layout, memory management, test code, etc.) which has proved to work quite well for libraries of this type. There is also the performance argument. Some core functions will benefit from optimizations that are natural in C such as in-place operations and fine-grained manual memory management. However, the performance aspect should not be overemphasized: Calcium will spend most of its time in Flint and Arb kernel functions and this would probably still be true even if it were written in a slower language. There are certainly types of mathematical functionality that will be too inconvenient to implement in C. Our intention is indeed to leave such functionality to projects written in Python, Julia, etc. which may then opt to depend on Calcium for basic operations. **What is the development status of Calcium?** Calcium is presently in early development and should be considered experimental software. The interfaces are subject to change and many important functions and optimizations have not been implemented. A more stable and functional release can be expected in late 2021. .. raw:: latex \newpage calcium-0.4.1/doc/source/pycalcium.rst000066400000000000000000000004601407704557200177310ustar00rootroot00000000000000.. _pycalcium: Python interface (pycalcium / pyca) =============================================================================== .. automodule:: pyca :members: :inherited-members: :undoc-members: :special-members: __init__ , __bool__ :member-order: bysource .. raw:: latex \newpage calcium-0.4.1/doc/source/qqbar.rst000066400000000000000000001255741407704557200170670ustar00rootroot00000000000000.. _qqbar: **qqbar.h** -- algebraic numbers represented by minimal polynomials =============================================================================== A :type:`qqbar_t` represents a real or complex algebraic number (an element of `\overline{\mathbb{Q}}`) by its unique reduced minimal polynomial in `\mathbb{Z}[x]` and an isolating complex interval. The precision of isolating intervals is maintained automatically to ensure that all operations on :type:`qqbar_t` instances are exact. This representation is useful for working with individual algebraic numbers of moderate degree (up to 100, say). Arithmetic in this representation is expensive: an arithmetic operation on numbers of degrees *m* and *n* involves computing and then factoring an annihilating polynomial of degree *mn* and potentially also performing numerical root-finding. For doing repeated arithmetic, it is generally more efficient to work with the :type:`ca_t` type in a fixed number field. The :type:`qqbar_t` type is used internally by the :type:`ca_t` type to represent the embedding of number fields in `\mathbb{R}` or `\mathbb{C}` and to decide predicates for algebraic numbers. Types and macros ------------------------------------------------------------------------------- .. type:: qqbar_struct .. type:: qqbar_t A *qqbar_struct* consists of an *fmpz_poly_struct* and an *acb_struct*. A *qqbar_t* is defined as an array of length one of type *qqbar_struct*, permitting a *qqbar_t* to be passed by reference. .. type:: qqbar_ptr Alias for ``qqbar_struct *``, used for *qqbar* vectors. .. type:: qqbar_srcptr Alias for ``const qqbar_struct *``, used for *qqbar* vectors when passed as readonly input to functions. .. macro:: QQBAR_POLY(x) Macro returning a pointer to the minimal polynomial of *x* which can be used as an *fmpz_poly_t*. .. macro:: QQBAR_COEFFS(x) Macro returning a pointer to the array of *fmpz* coefficients of the minimal polynomial of *x*. .. macro:: QQBAR_ENCLOSURE(x) Macro returning a pointer to the enclosure of *x* which can be used as an *acb_t*. Memory management ------------------------------------------------------------------------------- .. function:: void qqbar_init(qqbar_t res) Initializes the variable *res* for use, and sets its value to zero. .. function:: void qqbar_clear(qqbar_t res) Clears the variable *res*, freeing or recycling its allocated memory. .. function:: qqbar_ptr _qqbar_vec_init(slong len) Returns a pointer to an array of *len* initialized *qqbar_struct*:s. .. function:: void _qqbar_vec_clear(qqbar_ptr vec, slong len) Clears all *len* entries in the vector *vec* and frees the vector itself. Assignment ------------------------------------------------------------------------------- .. function:: void qqbar_swap(qqbar_t x, qqbar_t y) Swaps the values of *x* and *y* efficiently. .. function:: void qqbar_set(qqbar_t res, const qqbar_t x) void qqbar_set_si(qqbar_t res, slong x) void qqbar_set_ui(qqbar_t res, ulong x) void qqbar_set_fmpz(qqbar_t res, const fmpz_t x) void qqbar_set_fmpq(qqbar_t res, const fmpq_t x) Sets *res* to the value *x*. .. function:: void qqbar_set_re_im(qqbar_t res, const qqbar_t x, const qqbar_t y) Sets *res* to the value `x + yi`. .. function:: int qqbar_set_d(qqbar_t res, double x) int qqbar_set_re_im_d(qqbar_t res, double x, double y) Sets *res* to the value *x* or `x + yi` respectively. These functions performs error handling: if *x* and *y* are finite, the conversion succeeds and the return flag is 1. If *x* or *y* is non-finite (infinity or NaN), the conversion fails and the return flag is 0. Properties ------------------------------------------------------------------------------- .. function:: slong qqbar_degree(const qqbar_t x) Returns the degree of *x*, i.e. the degree of the minimal polynomial. .. function:: int qqbar_is_rational(const qqbar_t x) Returns whether *x* is a rational number. .. function:: int qqbar_is_integer(const qqbar_t x) Returns whether *x* is an integer (an element of `\mathbb{Z}`). .. function:: int qqbar_is_algebraic_integer(const qqbar_t x) Returns whether *x* is an algebraic integer, i.e. whether its minimal polynomial has leading coefficient 1. .. function:: int qqbar_is_zero(const qqbar_t x) int qqbar_is_one(const qqbar_t x) int qqbar_is_neg_one(const qqbar_t x) Returns whether *x* is the number `0`, `1`, `-1`. .. function:: int qqbar_is_i(const qqbar_t x) int qqbar_is_neg_i(const qqbar_t x) Returns whether *x* is the imaginary unit `i` (respectively `-i`). .. function:: int qqbar_is_real(const qqbar_t x) Returns whether *x* is a real number. .. function:: void qqbar_height(fmpz_t res, const qqbar_t x) Sets *res* to the height of *x* (the largest absolute value of the coefficients of the minimal polynomial of *x*). .. function:: slong qqbar_height_bits(const qqbar_t x) Returns the height of *x* (the largest absolute value of the coefficients of the minimal polynomial of *x*) measured in bits. .. function:: int qqbar_within_limits(const qqbar_t x, slong deg_limit, slong bits_limit) Checks if *x* has degree bounded by *deg_limit* and height bounded by *bits_limit* bits, returning 0 (false) or 1 (true). If *deg_limit* is set to 0, the degree check is skipped, and similarly for *bits_limit*. .. function:: int qqbar_binop_within_limits(const qqbar_t x, const qqbar_t y, slong deg_limit, slong bits_limit) Checks if `x + y`, `x - y`, `x \cdot y` and `x / y` certainly have degree bounded by *deg_limit* (by multiplying the degrees for *x* and *y* to obtain a trivial bound). For *bits_limits*, the sum of the bit heights of *x* and *y* is checked against the bound (this is only a heuristic). If *deg_limit* is set to 0, the degree check is skipped, and similarly for *bits_limit*. Conversions ------------------------------------------------------------------------------- .. function:: void _qqbar_get_fmpq(fmpz_t num, fmpz_t den, const qqbar_t x) Sets *num* and *den* to the numerator and denominator of *x*. Aborts if *x* is not a rational number. .. function:: void qqbar_get_fmpq(fmpq_t res, const qqbar_t x) Sets *res* to *x*. Aborts if *x* is not a rational number. .. function:: void qqbar_get_fmpz(fmpz_t res, const qqbar_t x) Sets *res* to *x*. Aborts if *x* is not an integer. Special values ------------------------------------------------------------------------------- .. function:: void qqbar_zero(qqbar_t res) Sets *res* to the number 0. .. function:: void qqbar_one(qqbar_t res) Sets *res* to the number 1. .. function:: void qqbar_i(qqbar_t res) Sets *res* to the imaginary unit `i`. .. function:: void qqbar_phi(qqbar_t res) Sets *res* to the golden ratio `\varphi = \tfrac{1}{2}(\sqrt{5} + 1)`. Input and output ------------------------------------------------------------------------------- .. function:: void qqbar_print(const qqbar_t x) Prints *res* to standard output. The output shows the degree and the list of coefficients of the minimal polynomial followed by a decimal representation of the enclosing interval. This function is mainly intended for debugging. .. function:: void qqbar_printn(const qqbar_t x, slong n) Prints *res* to standard output. The output shows a decimal approximation to *n* digits. .. function:: void qqbar_printnd(const qqbar_t x, slong n) Prints *res* to standard output. The output shows a decimal approximation to *n* digits, followed by the degree of the number. For example, *print*, *printn* and *printnd* with `n = 6` give the following output for the numbers 0, 1, `i`, `\varphi`, `\sqrt{2}-\sqrt{3} i`: .. code :: deg 1 [0, 1] 0 deg 1 [-1, 1] 1.00000 deg 2 [1, 0, 1] 1.00000*I deg 2 [-1, -1, 1] [1.61803398874989484820458683436563811772 +/- 6.00e-39] deg 4 [25, 0, 2, 0, 1] [1.4142135623730950488016887242096980786 +/- 8.67e-38] + [-1.732050807568877293527446341505872367 +/- 1.10e-37]*I 0 1.00000 1.00000*I 1.61803 1.41421 - 1.73205*I 0 (deg 1) 1.00000 (deg 1) 1.00000*I (deg 2) 1.61803 (deg 2) 1.41421 - 1.73205*I (deg 4) Random generation ------------------------------------------------------------------------------- .. function:: void qqbar_randtest(qqbar_t res, flint_rand_t state, slong deg, slong bits) Sets *res* to a random algebraic number with degree up to *deg* and with height (measured in bits) up to *bits*. .. function:: void qqbar_randtest_real(qqbar_t res, flint_rand_t state, slong deg, slong bits) Sets *res* to a random real algebraic number with degree up to *deg* and with height (measured in bits) up to *bits*. .. function:: void qqbar_randtest_nonreal(qqbar_t res, flint_rand_t state, slong deg, slong bits) Sets *res* to a random nonreal algebraic number with degree up to *deg* and with height (measured in bits) up to *bits*. Since all algebraic numbers of degree 1 are real, *deg* must be at least 2. Comparisons ------------------------------------------------------------------------------- .. function:: int qqbar_equal(const qqbar_t x, const qqbar_t y) Returns whether *x* and *y* are equal. .. function:: int qqbar_equal_fmpq_poly_val(const qqbar_t x, const fmpq_poly_t f, const qqbar_t y) Returns whether *x* is equal to `f(y)`. This function is more efficient than evaluating `f(y)` and comparing the results. .. function:: int qqbar_cmp_re(const qqbar_t x, const qqbar_t y) Compares the real parts of *x* and *y*, returning -1, 0 or +1. .. function:: int qqbar_cmp_im(const qqbar_t x, const qqbar_t y) Compares the imaginary parts of *x* and *y*, returning -1, 0 or +1. .. function:: int qqbar_cmpabs_re(const qqbar_t x, const qqbar_t y) Compares the absolute values of the real parts of *x* and *y*, returning -1, 0 or +1. .. function:: int qqbar_cmpabs_im(const qqbar_t x, const qqbar_t y) Compares the absolute values of the imaginary parts of *x* and *y*, returning -1, 0 or +1. .. function:: int qqbar_cmpabs(const qqbar_t x, const qqbar_t y) Compares the absolute values of *x* and *y*, returning -1, 0 or +1. .. function:: int qqbar_cmp_root_order(const qqbar_t x, const qqbar_t y) Compares *x* and *y* using an arbitrary but convenient ordering defined on the complex numbers. This is useful for sorting the roots of a polynomial in a canonical order. We define the root order as follows: real roots come first, in descending order. Nonreal roots are subsequently ordered first by real part in descending order, then in ascending order by the absolute value of the imaginary part, and then in descending order of the sign. This implies that complex conjugate roots are adjacent, with the root in the upper half plane first. .. function:: ulong qqbar_hash(const qqbar_t x) Returns a hash of *x*. As currently implemented, this function only hashes the minimal polynomial of *x*. The user should mix in some bits based on the numerical value if it is critical to distinguish between conjugates of the same minimal polynomial. This function is also likely to produce serial runs of values for lexicographically close minimal polynomials. This is not necessarily a problem for use in hash tables, but if it is important that all bits in the output are random, the user should apply an integer hash function to the output. Complex parts ------------------------------------------------------------------------------- .. function:: void qqbar_conj(qqbar_t res, const qqbar_t x) Sets *res* to the complex conjugate of *x*. .. function:: void qqbar_re(qqbar_t res, const qqbar_t x) Sets *res* to the real part of *x*. .. function:: void qqbar_im(qqbar_t res, const qqbar_t x) Sets *res* to the imaginary part of *x*. .. function:: void qqbar_re_im(qqbar_t res1, qqbar_t res2, const qqbar_t x) Sets *res1* to the real part of *x* and *res2* to the imaginary part of *x*. .. function:: void qqbar_abs(qqbar_t res, const qqbar_t x) Sets *res* to the absolute value of *x*: .. function:: void qqbar_abs2(qqbar_t res, const qqbar_t x) Sets *res* to the square of the absolute value of *x*. .. function:: void qqbar_sgn(qqbar_t res, const qqbar_t x) Sets *res* to the complex sign of *x*, defined as 0 if *x* is zero and as `x / |x|` otherwise. .. function:: int qqbar_sgn_re(const qqbar_t x) Returns the sign of the real part of *x* (-1, 0 or +1). .. function:: int qqbar_sgn_im(const qqbar_t x) Returns the sign of the imaginary part of *x* (-1, 0 or +1). .. function:: int qqbar_csgn(const qqbar_t x) Returns the extension of the real sign function taking the value 1 for *x* strictly in the right half plane, -1 for *x* strictly in the left half plane, and the sign of the imaginary part when *x* is on the imaginary axis. Equivalently, `\operatorname{csgn}(x) = x / \sqrt{x^2}` except that the value is 0 when *x* is zero. Integer parts ------------------------------------------------------------------------------- .. function:: void qqbar_floor(fmpz_t res, const qqbar_t x) Sets *res* to the floor function of *x*. If *x* is not real, the value is defined as the floor function of the real part of *x*. .. function:: void qqbar_ceil(fmpz_t res, const qqbar_t x) Sets *res* to the ceiling function of *x*. If *x* is not real, the value is defined as the ceiling function of the real part of *x*. Arithmetic ------------------------------------------------------------------------------- .. function:: void qqbar_neg(qqbar_t res, const qqbar_t x) Sets *res* to the negation of *x*. .. function:: void qqbar_add(qqbar_t res, const qqbar_t x, const qqbar_t y) void qqbar_add_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y) void qqbar_add_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y) void qqbar_add_ui(qqbar_t res, const qqbar_t x, ulong y) void qqbar_add_si(qqbar_t res, const qqbar_t x, slong y) Sets *res* to the sum of *x* and *y*. .. function:: void qqbar_sub(qqbar_t res, const qqbar_t x, const qqbar_t y) void qqbar_sub_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y) void qqbar_sub_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y) void qqbar_sub_ui(qqbar_t res, const qqbar_t x, ulong y) void qqbar_sub_si(qqbar_t res, const qqbar_t x, slong y) void qqbar_fmpq_sub(qqbar_t res, const fmpq_t x, const qqbar_t y) void qqbar_fmpz_sub(qqbar_t res, const fmpz_t x, const qqbar_t y) void qqbar_ui_sub(qqbar_t res, ulong x, const qqbar_t y) void qqbar_si_sub(qqbar_t res, slong x, const qqbar_t y) Sets *res* to the difference of *x* and *y*. .. function:: void qqbar_mul(qqbar_t res, const qqbar_t x, const qqbar_t y) void qqbar_mul_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y) void qqbar_mul_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y) void qqbar_mul_ui(qqbar_t res, const qqbar_t x, ulong y) void qqbar_mul_si(qqbar_t res, const qqbar_t x, slong y) Sets *res* to the product of *x* and *y*. .. function:: void qqbar_mul_2exp_si(qqbar_t res, const qqbar_t x, slong e) Sets *res* to *x* multiplied by `2^e`. .. function:: void qqbar_sqr(qqbar_t res, const qqbar_t x) Sets *res* to the square of *x*. .. function:: void qqbar_inv(qqbar_t res, const qqbar_t x, const qqbar_t y) Sets *res* to the multiplicative inverse of *y*. Division by zero calls *flint_abort*. .. function:: void qqbar_div(qqbar_t res, const qqbar_t x, const qqbar_t y) void qqbar_div_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y) void qqbar_div_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y) void qqbar_div_ui(qqbar_t res, const qqbar_t x, ulong y) void qqbar_div_si(qqbar_t res, const qqbar_t x, slong y) void qqbar_fmpq_div(qqbar_t res, const fmpq_t x, const qqbar_t y) void qqbar_fmpz_div(qqbar_t res, const fmpz_t x, const qqbar_t y) void qqbar_ui_div(qqbar_t res, ulong x, const qqbar_t y) void qqbar_si_div(qqbar_t res, slong x, const qqbar_t y) Sets *res* to the quotient of *x* and *y*. Division by zero calls *flint_abort*. .. function:: void qqbar_scalar_op(qqbar_t res, const qqbar_t x, const fmpz_t a, const fmpz_t b, const fmpz_t c) Sets *res* to the rational affine transformation `(ax+b)/c`, performed as a single operation. There are no restrictions on *a*, *b* and *c* except that *c* must be nonzero. Division by zero calls *flint_abort*. Powers and roots ------------------------------------------------------------------------------- .. function:: void qqbar_sqrt(qqbar_t res, const qqbar_t x) void qqbar_sqrt_ui(qqbar_t res, ulong x) Sets *res* to the principal square root of *x*. .. function:: void qqbar_rsqrt(qqbar_t res, const qqbar_t x) Sets *res* to the reciprocal of the principal square root of *x*. Division by zero calls *flint_abort*. .. function:: void qqbar_pow_ui(qqbar_t res, const qqbar_t x, ulong n) void qqbar_pow_si(qqbar_t res, const qqbar_t x, ulong n) void qqbar_pow_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t n) void qqbar_pow_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t n) Sets *res* to *x* raised to the *n*-th power. Raising zero to a negative power aborts. .. function:: void qqbar_root_ui(qqbar_t res, const qqbar_t x, ulong n) void qqbar_fmpq_root_ui(qqbar_t res, const fmpq_t x, ulong n) Sets *res* to the principal *n*-th root of *x*. The order *n* must be positive. .. function:: void qqbar_fmpq_pow_si_ui(qqbar_t res, const fmpq_t x, slong m, ulong n) Sets *res* to the principal branch of `x^{m/n}`. The order *n* must be positive. Division by zero calls *flint_abort*. .. function:: int qqbar_pow(qqbar_t res, const qqbar_t x, const qqbar_t y) General exponentiation: if `x^y` is an algebraic number, sets *res* to this value and returns 1. If `x^y` is transcendental or undefined, returns 0. Note that this function returns 0 instead of aborting on division zero. Numerical enclosures ------------------------------------------------------------------------------- The following functions guarantee a polished output in which both the real and imaginary parts are accurate to *prec* bits and exact when exactly representable (that is, when a real or imaginary part is a sufficiently small dyadic number). In some cases, the computations needed to polish the output may be expensive. When polish is unnecessary, :func:`qqbar_enclosure_raw` may be used instead. Alternatively, :func:`qqbar_cache_enclosure` can be used to avoid recomputations. .. function:: void qqbar_get_acb(acb_t res, const qqbar_t x, slong prec) Sets *res* to an enclosure of *x* rounded to *prec* bits. .. function:: void qqbar_get_arb(arb_t res, const qqbar_t x, slong prec) Sets *res* to an enclosure of *x* rounded to *prec* bits, assuming that *x* is a real number. If *x* is not real, *res* is set to `[\operatorname{NaN} \pm \infty]`. .. function:: void qqbar_get_arb_re(arb_t res, const qqbar_t x, slong prec) Sets *res* to an enclosure of the real part of *x* rounded to *prec* bits. .. function:: void qqbar_get_arb_im(arb_t res, const qqbar_t x, slong prec) Sets *res* to an enclosure of the imaginary part of *x* rounded to *prec* bits. .. function:: void qqbar_cache_enclosure(qqbar_t res, slong prec) Polishes the internal enclosure of *res* to at least *prec* bits of precision in-place. Normally, *qqbar* operations that need high-precision enclosures compute them on the fly without caching the results; if *res* will be used as an invariant operand for many operations, calling this function as a precomputation step can improve performance. Numerator and denominator ------------------------------------------------------------------------------- .. function:: void qqbar_denominator(fmpz_t res, const qqbar_t y) Sets *res* to the denominator of *y*, i.e. the leading coefficient of the minimal polynomial of *y*. .. function:: void qqbar_numerator(qqbar_t res, const qqbar_t y) Sets *res* to the numerator of *y*, i.e. *y* multiplied by its denominator. Conjugates ------------------------------------------------------------------------------- .. function:: void qqbar_conjugates(qqbar_ptr res, const qqbar_t x) Sets the entries of the vector *res* to the *d* algebraic conjugates of *x*, including *x* itself, where *d* is the degree of *x*. The output is sorted in a canonical order (as defined by :func:`qqbar_cmp_root_order`). Polynomial evaluation ------------------------------------------------------------------------------- .. function:: void _qqbar_evaluate_fmpq_poly(qqbar_t res, const fmpz * poly, const fmpz_t den, slong len, const qqbar_t x) void qqbar_evaluate_fmpq_poly(qqbar_t res, const fmpq_poly_t poly, const qqbar_t x) void _qqbar_evaluate_fmpz_poly(qqbar_t res, const fmpz * poly, slong len, const qqbar_t x) void qqbar_evaluate_fmpz_poly(qqbar_t res, const fmpz_poly_t poly, const qqbar_t x) Sets *res* to the value of the given polynomial *poly* evaluated at the algebraic number *x*. These methods detect simple special cases and automatically reduce *poly* if its degree is greater or equal to that of the minimal polynomial of *x*. In the generic case, evaluation is done by computing minimal polynomials of representation matrices. .. function:: int qqbar_evaluate_fmpz_mpoly_iter(qqbar_t res, const fmpz_mpoly_t poly, qqbar_srcptr x, slong deg_limit, slong bits_limit, const fmpz_mpoly_ctx_t ctx) int qqbar_evaluate_fmpz_mpoly_horner(qqbar_t res, const fmpz_mpoly_t poly, qqbar_srcptr x, slong deg_limit, slong bits_limit, const fmpz_mpoly_ctx_t ctx) int qqbar_evaluate_fmpz_mpoly(qqbar_t res, const fmpz_mpoly_t poly, qqbar_srcptr x, slong deg_limit, slong bits_limit, const fmpz_mpoly_ctx_t ctx) Sets *res* to the value of *poly* evaluated at the algebraic numbers given in the vector *x*. The number of variables is defined by the context object *ctx*. The parameters *deg_limit* and *bits_limit* define evaluation limits: if any temporary result exceeds these limits (not necessarily the final value, in case of cancellation), the evaluation is aborted and 0 (failure) is returned. If evaluation succeeds, 1 is returned. The *iter* version iterates over all terms in succession and computes the powers that appear. The *horner* version uses a multivariate implementation of the Horner scheme. The default algorithm currently uses the Horner scheme. Polynomial roots ------------------------------------------------------------------------------- .. function:: void qqbar_roots_fmpz_poly(qqbar_ptr res, const fmpz_poly_t poly, int flags) void qqbar_roots_fmpq_poly(qqbar_ptr res, const fmpq_poly_t poly, int flags) Sets the entries of the vector *res* to the *d* roots of the polynomial *poly*. Roots with multiplicity appear with repetition in the output array. By default, the roots will be sorted in a convenient canonical order (as defined by :func:`qqbar_cmp_root_order`). Instances of a repeated root always appear consecutively. The following *flags* are supported: - QQBAR_ROOTS_IRREDUCIBLE - if set, *poly* is assumed to be irreducible (it may still have constant content), and no polynomial factorization is performed internally. - QQBAR_ROOTS_UNSORTED - if set, the roots will not be guaranteed to be sorted (except for repeated roots being listed consecutively). .. function:: void qqbar_eigenvalues_fmpz_mat(qqbar_ptr res, const fmpz_mat_t mat, int flags) void qqbar_eigenvalues_fmpq_mat(qqbar_ptr res, const fmpz_mat_t mat, int flags) Sets the entries of the vector *res* to the eigenvalues of the square matrix *mat*. These functions compute the characteristic polynomial of *mat* and then call :func:`qqbar_roots_fmpz_poly` with the same flags. Roots of unity and trigonometric functions ------------------------------------------------------------------------------- The following functions use word-size integers *p* and *q* instead of *fmpq_t* instances to express rational numbers. This is to emphasize that the computations are feasible only with small *q* in this representation of algebraic numbers since the associated minimal polynomials have degree `O(q)`. The input *p* and *q* do not need to be reduced *a priori*, but should not be close to the word boundaries (they may be added and subtracted internally). .. function:: void qqbar_root_of_unity(qqbar_t res, slong p, ulong q) Sets *res* to the root of unity `e^{2 \pi i p / q}`. .. function:: int qqbar_is_root_of_unity(slong * p, ulong * q, const qqbar_t x) If *x* is not a root of unity, returns 0. If *x* is a root of unity, returns 1. If *p* and *q* are not *NULL* and *x* is a root of unity, this also sets *p* and *q* to the minimal integers with `0 \le p < q` such that `x = e^{2 \pi i p / q}`. .. function:: void qqbar_exp_pi_i(qqbar_t res, slong p, ulong q) Sets *res* to the root of unity `e^{\pi i p / q}`. .. function:: void qqbar_cos_pi(qqbar_t res, slong p, ulong q) void qqbar_sin_pi(qqbar_t res, slong p, ulong q) int qqbar_tan_pi(qqbar_t res, slong p, ulong q) int qqbar_cot_pi(qqbar_t res, slong p, ulong q) int qqbar_sec_pi(qqbar_t res, slong p, ulong q) int qqbar_csc_pi(qqbar_t res, slong p, ulong q) Sets *res* to the trigonometric function `\cos(\pi x)`, `\sin(\pi x)`, etc., with `x = \tfrac{p}{q}`. The functions tan, cot, sec and csc return the flag 1 if the value exists, and return 0 if the evaluation point is a pole of the function. .. function:: int qqbar_log_pi_i(slong * p, ulong * q, const qqbar_t x) If `y = \operatorname{log}(x) / (\pi i)` is algebraic, and hence necessarily rational, sets `y = p / q` to the reduced such fraction with `-1 < y \le 1` and returns 1. If *y* is not algebraic, returns 0. .. function:: int qqbar_atan_pi(slong * p, ulong * q, const qqbar_t x) If `y = \operatorname{atan}(x) / \pi` is algebraic, and hence necessarily rational, sets `y = p / q` to the reduced such fraction with `|y| < \tfrac{1}{2}` and returns 1. If *y* is not algebraic, returns 0. .. function:: int qqbar_asin_pi(slong * p, ulong * q, const qqbar_t x) If `y = \operatorname{asin}(x) / \pi` is algebraic, and hence necessarily rational, sets `y = p / q` to the reduced such fraction with `|y| \le \tfrac{1}{2}` and returns 1. If *y* is not algebraic, returns 0. .. function:: int qqbar_acos_pi(slong * p, ulong * q, const qqbar_t x) If `y = \operatorname{acos}(x) / \pi` is algebraic, and hence necessarily rational, sets `y = p / q` to the reduced such fraction with `0 \le y \le 1` and returns 1. If *y* is not algebraic, returns 0. .. function:: int qqbar_acot_pi(slong * p, ulong * q, const qqbar_t x) If `y = \operatorname{acot}(x) / \pi` is algebraic, and hence necessarily rational, sets `y = p / q` to the reduced such fraction with `-\tfrac{1}{2} < y \le \tfrac{1}{2}` and returns 1. If *y* is not algebraic, returns 0. .. function:: int qqbar_asec_pi(slong * p, ulong * q, const qqbar_t x) If `y = \operatorname{asec}(x) / \pi` is algebraic, and hence necessarily rational, sets `y = p / q` to the reduced such fraction with `0 \le y \le 1` and returns 1. If *y* is not algebraic, returns 0. .. function:: int qqbar_acsc_pi(slong * p, ulong * q, const qqbar_t x) If `y = \operatorname{acsc}(x) / \pi` is algebraic, and hence necessarily rational, sets `y = p / q` to the reduced such fraction with `-\tfrac{1}{2} \le y \le \tfrac{1}{2}` and returns 1. If *y* is not algebraic, returns 0. Guessing and simplification ------------------------------------------------------------------------------- .. function:: int qqbar_guess(qqbar_t res, const acb_t z, slong max_deg, slong max_bits, int flags, slong prec) Attempts to find an algebraic number *res* of degree at most *max_deg* and height at most *max_bits* bits matching the numerical enclosure *z*. The return flag indicates success. This is only a heuristic method, and the return flag neither implies a rigorous proof that *res* is the correct result, nor a rigorous proof that no suitable algebraic number with the given *max_deg* and *max_bits* exists. (Proof of nonexistence could in principle be computed, but this is not yet implemented.) The working precision *prec* should normally be the same as the precision used to compute *z*. It does not make much sense to run this algorithm with precision smaller than O(*max_deg* · *max_bits*). This function does a single iteration at the target *max_deg*, *max_bits*, and *prec*. For best performance, one should invoke this function repeatedly with successively larger parameters when the size of the intended solution is unknown or may be much smaller than a worst-case bound. .. function:: int qqbar_express_in_field(fmpq_poly_t res, const qqbar_t alpha, const qqbar_t x, slong max_bits, int flags, slong prec) Attempts to express *x* in the number field generated by *alpha*, returning success (0 or 1). On success, *res* is set to a polynomial *f* of degree less than the degree of *alpha* and with height (counting both the numerator and the denominator, when the coefficients of *g* are put on a common denominator) bounded by *max_bits* bits, such that `f(\alpha) = x`. (Exception: the *max_bits* parameter is currently ignored if *x* is rational, in which case *res* is just set to the value of *x*.) This function looks for a linear relation heuristically using a working precision of *prec* bits. If *x* is expressible in terms of *alpha*, then this function is guaranteed to succeed when *prec* is taken large enough. The identity `f(\alpha) = x` is checked rigorously, i.e. a return value of 1 implies a proof of correctness. In principle, choosing a sufficiently large *prec* can be used to prove that *x* does not lie in the field generated by *alpha*, but the present implementation does not support doing so automatically. This function does a single iteration at the target *max_bits* and and *prec*. For best performance, one should invoke this function repeatedly with successively larger parameters when the size of the intended solution is unknown or may be much smaller than a worst-case bound. Symbolic expressions and conversion to radicals ------------------------------------------------------------------------------- .. function:: void qqbar_get_quadratic(fmpz_t a, fmpz_t b, fmpz_t c, const fmpz_t q, const qqbar_t x, int factoring) Assuming that *x* has degree 1 or 2, computes integers *a*, *b*, *c* and *q* such that .. math :: x = \frac{a + b \sqrt{c}}{q} and such that *c* is not a perfect square, *q* is positive, and *q* has no content in common with both *a* and *b*. In other words, this determines a quadratic field `\mathbb{Q}(\sqrt{c})` containing *x*, and then finds the canonical reduced coefficients *a*, *b* and *q* expressing *x* in this field. For convenience, this function supports rational *x*, for which *b* and *c* will both be set to zero. The following remarks apply to irrationals. The radicand *c* will not be a perfect square, but will not automatically be squarefree since this would require factoring the discriminant. As a special case, *c* will be set to `-1` if *x* is a Gaussian rational number. Otherwise, behavior is controlled by the *factoring* parameter. * If *factoring* is 0, no factorization is performed apart from removing powers of two. * If *factoring* is 1, a complete factorization is performed (*c* will be minimal). This can be very expensive if the discriminant is large. * If *factoring* is 2, a smooth factorization is performed to remove small factors from *c*. This is a tradeoff that provides pretty output in most cases while avoiding extreme worst-case slowdown. The smooth factorization guarantees finding all small factors (up to some trial division limit determined internally by Flint), but large factors are only found heuristically. .. function:: int qqbar_set_fexpr(qqbar_t res, const fexpr_t expr) Sets *res* to the algebraic number represented by the symbolic expression *expr*, returning 1 on success and 0 on failure. This function performs a "static" evaluation using *qqbar* arithmetic, supporting only closed-form expressions with explicitly algebraic subexpressions. It can be used to recover values generated by :func:`qqbar_get_expr_formula` and variants. For evaluating more complex expressions involving other types of values or requiring symbolic simplifications, the user should preprocess *expr* so that it is in a form which can be parsed by :func:`qqbar_set_fexpr`. The following expressions are supported: * Integer constants * Arithmetic operations with algebraic operands * Square roots of algebraic numbers * Powers with algebraic base and exponent an explicit rational number * NumberI, GoldenRatio, RootOfUnity * Floor, Ceil, Abs, Sign, Csgn, Conjugate, Re, Im, Max, Min * Trigonometric functions with argument an explicit rational number times Pi * Exponentials with argument an explicit rational number times Pi * NumberI * The Decimal() constructor * AlgebraicNumberSerialized() (assuming valid data, which is not checked) * PolynomialRootIndexed() * PolynomialRootNearest() Examples of formulas that are not supported, despite the value being an algebraic number: * ``Pi - Pi`` (general transcendental simplifications are not performed) * ``1 / Infinity`` (only numbers are handled) * ``Sum(n, For(n, 1, 10))`` (only static evaluation is performed) .. function:: void qqbar_get_fexpr_repr(fexpr_t res, const qqbar_t x) Sets *res* to a symbolic expression reflecting the exact internal representation of *x*. The output will have the form ``AlgebraicNumberSerialized(List(coeffs), enclosure)``. The output can be converted back to a ``qqbar_t`` value using :func:`qqbar_set_fexpr`. This is the recommended format for serializing algebraic numbers as it requires minimal computation, but it has the disadvantage of not being human-readable. .. function:: void qqbar_get_fexpr_root_nearest(fexpr_t res, const qqbar_t x) Sets *res* to a symbolic expression unambiguously describing *x* in the form ``PolynomialRootNearest(List(coeffs), point)`` where *point* is an approximation of *x* guaranteed to be closer to *x* than any conjugate root. The output can be converted back to a ``qqbar_t`` value using :func:`qqbar_set_fexpr`. This is a useful format for human-readable presentation, but serialization and deserialization can be expensive. .. function:: void qqbar_get_fexpr_root_indexed(fexpr_t res, const qqbar_t x) Sets *res* to a symbolic expression unambiguously describing *x* in the form ``PolynomialRootIndexed(List(coeffs), index)`` where *index* is the index of *x* among its conjugate roots in the builtin root sort order. The output can be converted back to a ``qqbar_t`` value using :func:`qqbar_set_fexpr`. This is a useful format for human-readable presentation when the numerical value is important, but serialization and deserialization can be expensive. .. function:: int qqbar_get_fexpr_formula(fexpr_t res, const qqbar_t x, ulong flags) Attempts to express the algebraic number *x* as a closed-form expression using arithmetic operations, radicals, and possibly exponentials or trigonometric functions, but without using ``PolynomialRootNearest`` or ``PolynomialRootIndexed``. Returns 0 on failure and 1 on success. The *flags* parameter toggles different methods for generating formulas. It can be set to any combination of the following. If *flags* is 0, only rational numbers will be handled. .. macro:: QQBAR_FORMULA_ALL Toggles all methods (potentially expensive). .. macro:: QQBAR_FORMULA_GAUSSIANS Detect Gaussian rational numbers `a + bi`. .. macro:: QQBAR_FORMULA_QUADRATICS Solve quadratics in the form `a + b \sqrt{d}`. .. macro:: QQBAR_FORMULA_CYCLOTOMICS Detect elements of cyclotomic fields. This works by trying plausible cyclotomic fields (based on the degree of the input), using LLL to find candidate number field elements, and certifying candidates through an exact computation. Detection is heuristic and is not guaranteed to find all cyclotomic numbers. .. macro:: QQBAR_FORMULA_CUBICS QQBAR_FORMULA_QUARTICS QQBAR_FORMULA_QUINTICS Solve polynomials of degree 3, 4 and (where applicable) 5 using cubic, quartic and quintic formulas (not yet implemented). .. macro:: QQBAR_FORMULA_DEPRESSION Use depression to try to generate simpler numbers. .. macro:: QQBAR_FORMULA_DEFLATION Use deflation to try to generate simpler numbers. This allows handling number of the form `a^{1/n}` where *a* can be represented in closed form. .. macro:: QQBAR_FORMULA_SEPARATION Try separating real and imaginary parts or sign and magnitude of complex numbers. This allows handling numbers of the form `a + bi` or `m \cdot s` (with `m > 0, |s| = 1`) where *a* and *b* or *m* and *s* can be represented in closed form. This is only attempted as a fallback after other methods fail: if an explicit Cartesian or magnitude-sign represented is desired, the user should manually separate the number into complex parts before calling :func:`qqbar_get_fexpr_formula`. .. macro:: QQBAR_FORMULA_EXP_FORM QQBAR_FORMULA_TRIG_FORM QQBAR_FORMULA_RADICAL_FORM QQBAR_FORMULA_AUTO_FORM Select output form for cyclotomic numbers. The *auto* form (equivalent to no flags being set) results in radicals for numbers of low degree, trigonometric functions for real numbers, and complex exponentials for nonreal numbers. The other flags (not fully implemented) can be used to force exponential form, trigonometric form, or radical form. Internal functions ------------------------------------------------------------------------------- .. function:: void qqbar_fmpz_poly_composed_op(fmpz_poly_t res, const fmpz_poly_t A, const fmpz_poly_t B, int op) Given nonconstant polynomials *A* and *B*, sets *res* to a polynomial whose roots are `a+b`, `a-b`, `ab` or `a/b` for all roots *a* of *A* and all roots *b* of *B*. The parameter *op* selects the arithmetic operation: 0 for addition, 1 for subtraction, 2 for multiplication and 3 for division. If *op* is 3, *B* must not have zero as a root. .. function:: void qqbar_binary_op(qqbar_t res, const qqbar_t x, const qqbar_t y, int op) Performs a binary operation using a generic algorithm. This does not check for special cases. .. function:: int _qqbar_validate_uniqueness(acb_t res, const fmpz_poly_t poly, const acb_t z, slong max_prec) Given *z* known to be an enclosure of at least one root of *poly*, certifies that the enclosure contains a unique root, and in that case sets *res* to a new (possibly improved) enclosure for the same root, returning 1. Returns 0 if uniqueness cannot be certified. The enclosure is validated by performing a single step with the interval Newton method. The working precision is determined from the accuracy of *z*, but limited by *max_prec* bits. This method slightly inflates the enclosure *z* to improve the chances that the interval Newton step will succeed. Uniqueness on this larger interval implies uniqueness of the original interval, but not existence; when existence has not been ensured a priori, :func:`_qqbar_validate_existence_uniqueness` should be used instead. .. function:: int _qqbar_validate_existence_uniqueness(acb_t res, const fmpz_poly_t poly, const acb_t z, slong max_prec) Given any complex interval *z*, certifies that the enclosure contains a unique root of *poly*, and in that case sets *res* to a new (possibly improved) enclosure for the same root, returning 1. Returns 0 if existence and uniqueness cannot be certified. The enclosure is validated by performing a single step with the interval Newton method. The working precision is determined from the accuracy of *z*, but limited by *max_prec* bits. .. function:: void _qqbar_enclosure_raw(acb_t res, const fmpz_poly_t poly, const acb_t z, slong prec) void qqbar_enclosure_raw(acb_t res, const qqbar_t x, slong prec) Sets *res* to an enclosure of *x* accurate to about *prec* bits (the actual accuracy can be slightly lower, or higher). This function uses repeated interval Newton steps to polish the initial enclosure *z*, doubling the working precision each time. If any step fails to improve the accuracy significantly, the root is recomputed from scratch to higher precision. If the initial enclosure is accurate enough, *res* is set to this value without rounding and without further computation. .. function:: int _qqbar_acb_lindep(fmpz * rel, acb_srcptr vec, slong len, int check, slong prec) Attempts to find an integer vector *rel* giving a linear relation between the elements of the real or complex vector *vec*, using the LLL algorithm. The working precision is set to the minimum of *prec* and the relative accuracy of *vec* (that is, the difference between the largest magnitude and the largest error magnitude within *vec*). 95% of the bits within the working precision are used for the LLL matrix, and the remaining 5% bits are used to validate the linear relation by evaluating the linear combination and checking that the resulting interval contains zero. This validation does not prove the existence or nonexistence of a linear relation, but it provides a quick heuristic way to eliminate spurious relations. If *check* is set, the return value indicates whether the validation was successful; otherwise, the return value simply indicates whether the algorithm was executed normally (failure may occur, for example, if the input vector is non-finite). In principle, this method can be used to produce a proof that no linear relation exists with coefficients up to a specified bit size, but this has not yet been implemented. .. raw:: latex \newpage calcium-0.4.1/doc/source/setup.rst000066400000000000000000000072351407704557200171120ustar00rootroot00000000000000.. _setup: Setup =============================================================================== Installation ------------------------------------------------------------------------------- Calcium has the following dependencies: * FLINT (http://www.flintlib.org) and its dependencies (GMP/MPIR and MPFR). Calcium will require FLINT 2.7 (unreleased) or later; currently a git checkout of https://github.com/wbhart/flint2 is necessary. * Arb (http://arblib.org) version 2.18.1 or later. * Antic (https://github.com/wbhart/antic/) - use a git checkout. To compile, test and install Calcium from source assuming that all dependencies have been installed, run the following commands in the source directory:: ./configure make make check (optional) make install If GMP/MPIR, MPFR, FLINT, Arb or Antic are installed in some other location than the default path ``/usr/local``, pass ``--with-gmp=...``, ``--with-mpfr=...``, ``--with-flint=...``, ``--with-arb=...``, ``--with-antic=...`` with the correct path to configure (type ``./configure --help`` to show more options). After the installation, you may have to run ``ldconfig`` to make sure that the system's dynamic linker finds the library. On a multicore system, ``make`` can be run with the ``-j`` flag to build in parallel. For example, use ``make -j4`` on a quad-core machine. Running tests ------------------------------------------------------------------------------- After running ``make``, it is recommended to also run ``make check`` to verify that all unit tests pass. By default, the unit tests run a large number of iterations to improve the chances of detecting subtle problems. The test suite will take several minutes on a single core (``make -jN check`` if you have more cores to spare). You can adjust the number of test iterations via the ``CALCIUM_TEST_MULTIPLIER`` environment variable. For example, the following will only run 10% of the default iterations:: export CALCIUM_TEST_MULTIPLIER=0.1 make check It is also possible to run the unit tests for a single module, for instance:: make check MOD=ca Running code ------------------------------------------------------------------------------- Here is an example program to get started using Calcium: .. code-block:: c #include "calcium/ca.h" int main() { ca_ctx_t ctx; ca_t x; ca_ctx_init(ctx); ca_init(x, ctx); ca_pi(x, ctx); /* x = pi */ ca_sub_ui(x, x, 3, ctx); /* x = x - 3 */ ca_pow_ui(x, x, 2, ctx); /* x = x^2 */ ca_print(x, ctx); printf("\n"); printf("Computed with calcium-%s\n", calcium_version()); ca_clear(x, ctx); ca_ctx_clear(ctx); flint_cleanup(); return EXIT_SUCCESS; } Compile it with:: gcc test.c -lcalcium Depending on the environment, you may also have to pass the flags ``-larb``, ``-lantic``, ``-lflint``, ``-lmpfr``, ``-lgmp`` to the compiler. On some Debian based systems, ``-larb`` needs to be replaced with ``-lflint-arb``. If the header and library files are not in a standard location (``/usr/local`` on most systems), you may also have to provide flags such as:: -I/path/to/calcium -I/path/to/arb -I/path/to/flint -L/path/to/calcium -L/path/to/flint -L/path/to/arb Finally, to run the program, make sure that the linker can find the libraries. If they are installed in a nonstandard location, you can for example add this path to the ``LD_LIBRARY_PATH`` environment variable. The output of the example program should be something like the following:: 0.0200485 {a^2-6*a+9 where a = 3.14159 [Pi]} Computed with calcium-0.0.0 .. raw:: latex \newpage calcium-0.4.1/doc/source/utils_flint.rst000066400000000000000000000164461407704557200203120ustar00rootroot00000000000000.. _utils-flint: **utils_flint.h** -- extra methods for Flint types =============================================================================== General methods for multivariate polynomials ------------------------------------------------------------------------------- .. function:: void fmpz_mpoly_primitive_part(fmpz_mpoly_t res, const fmpz_mpoly_t f, const fmpz_mpoly_ctx_t ctx) Sets *res* to the primitive part of *f*, obtained by dividing out the content of all coefficients and normalizing the leading coefficient to be positive. The zero polynomial is unchanged. .. function:: void fmpz_mpoly_symmetric_gens(fmpz_mpoly_t res, ulong k, slong * vars, slong n, const fmpz_mpoly_ctx_t ctx) .. function:: void fmpz_mpoly_symmetric(fmpz_mpoly_t res, ulong k, const fmpz_mpoly_ctx_t ctx) Sets *res* to the elementary symmetric polynomial `e_k(X_1,\ldots,X_n)`. The *gens* version takes `X_1,\ldots,X_n` to be the subset of generators given by *vars* and *n*. The indices in *vars* start from zero. Currently, the indices in *vars* must be distinct. .. type:: fmpz_mpoly_vec_struct .. type:: fmpz_mpoly_vec_t A type holding a vector of :type:`fmpz_mpoly_t`. .. macro:: fmpz_mpoly_vec_entry(vec, i) Macro for accessing the entry at position *i* in *vec*. .. function:: void fmpz_mpoly_vec_init(fmpz_mpoly_vec_t vec, slong len, const fmpz_mpoly_ctx_t ctx) Initializes *vec* to a vector of length *len*, setting all entries to the zero polynomial. .. function::void fmpz_mpoly_vec_clear(fmpz_mpoly_vec_t vec, const fmpz_mpoly_ctx_t ctx) Clears *vec*, freeing its allocated memory. .. function:: void fmpz_mpoly_vec_print(const fmpz_mpoly_vec_t vec, const fmpz_mpoly_ctx_t ctx) Prints *vec* to standard output. .. function:: void fmpz_mpoly_vec_swap(fmpz_mpoly_vec_t x, fmpz_mpoly_vec_t y, const fmpz_mpoly_ctx_t ctx) Swaps *x* and *y* efficiently. .. function:: void fmpz_mpoly_vec_fit_length(fmpz_mpoly_vec_t vec, slong len, const fmpz_mpoly_ctx_t ctx) Allocates room for *len* entries in *vec*. .. function:: void fmpz_mpoly_vec_set(fmpz_mpoly_vec_t dest, const fmpz_mpoly_vec_t src, const fmpz_mpoly_ctx_t ctx) Sets *dest* to a copy of *src*. .. function:: void fmpz_mpoly_vec_append(fmpz_mpoly_vec_t vec, const fmpz_mpoly_t f, const fmpz_mpoly_ctx_t ctx) Appends *f* to the end of *vec*. .. function:: slong fmpz_mpoly_vec_insert_unique(fmpz_mpoly_vec_t vec, const fmpz_mpoly_t f, const fmpz_mpoly_ctx_t ctx) Inserts *f* without duplication into *vec* and returns its index. If this polynomial already exists, *vec* is unchanged. If this polynomial does not exist in *vec*, it is appended. .. function:: void fmpz_mpoly_vec_set_length(fmpz_mpoly_vec_t vec, slong len, const fmpz_mpoly_ctx_t ctx) Sets the length of *vec* to *len*, truncating or zero-extending as needed. .. function:: void fmpz_mpoly_vec_randtest_not_zero(fmpz_mpoly_vec_t vec, flint_rand_t state, slong len, slong poly_len, slong bits, ulong exp_bound, fmpz_mpoly_ctx_t ctx) Sets *vec* to a random vector with exactly *len* entries, all nonzero, with random parameters defined by *poly_len*, *bits* and *exp_bound*. .. function:: void fmpz_mpoly_vec_set_primitive_unique(fmpz_mpoly_vec_t res, const fmpz_mpoly_vec_t src, const fmpz_mpoly_ctx_t ctx) Sets *res* to a vector containing all polynomials in *src* reduced to their primitive parts, without duplication. The zero polynomial is skipped if present. The output order is arbitrary. Ideals and Gröbner bases ------------------------------------------------------------------------------- The following methods deal with ideals in `\mathbb{Q}[X_1,\ldots,X_n]`. We use primitive integer polynomials as normalised generators in place of monic rational polynomials. .. function:: void fmpz_mpoly_spoly(fmpz_mpoly_t res, const fmpz_mpoly_t f, const fmpz_mpoly_t g, const fmpz_mpoly_ctx_t ctx) Sets *res* to the *S*-polynomial of *f* and *g*, scaled to an integer polynomial by computing the LCM of the leading coefficients. .. function:: void fmpz_mpoly_reduction_primitive_part(fmpz_mpoly_t res, const fmpz_mpoly_t f, const fmpz_mpoly_vec_t vec, const fmpz_mpoly_ctx_t ctx) Sets *res* to the primitive part of the reduction (remainder of multivariate quasidivision with remainder) with respect to the polynomials *vec*. .. function:: int fmpz_mpoly_vec_is_groebner(const fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx) If *F* is *NULL*, checks if *G* is a Gröbner basis. If *F* is not *NULL*, checks if *G* is a Gröbner basis for *F*. .. function:: int fmpz_mpoly_vec_is_autoreduced(const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx) Checks whether the vector *F* is autoreduced (or inter-reduced). .. function:: void fmpz_mpoly_vec_autoreduction(fmpz_mpoly_vec_t H, const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx) Sets *H* to the autoreduction (inter-reduction) of *F*. .. function:: void fmpz_mpoly_vec_autoreduction_groebner(fmpz_mpoly_vec_t H, const fmpz_mpoly_vec_t G, const fmpz_mpoly_ctx_t ctx) Sets *H* to the autoreduction (inter-reduction) of *G*. Assumes that *G* is a Gröbner basis. This produces a reduced Gröbner basis, which is unique (up to the sort order of the entries in the vector). .. function:: pair_t fmpz_mpoly_select_pop_pair(pairs_t pairs, const fmpz_mpoly_vec_t G, const fmpz_mpoly_ctx_t ctx) Given a vector *pairs* of indices `(i, j)` into *G*, selects one pair for elimination in Buchberger's algorithm. The pair is removed from *pairs* and returned. .. function:: void fmpz_mpoly_buchberger_naive(fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx) Sets *G* to a Gröbner basis for *F*, computed using a naive implementation of Buchberger's algorithm. .. function:: int fmpz_mpoly_buchberger_naive_with_limits(fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t F, slong ideal_len_limit, slong poly_len_limit, slong poly_bits_limit, const fmpz_mpoly_ctx_t ctx) As :func:`fmpz_mpoly_buchberger_naive`, but halts if during the execution of Buchberger's algorithm the length of the ideal basis set exceeds *ideal_len_limit*, the length of any polynomial exceeds *poly_len_limit*, or the size of the coefficients of any polynomial exceeds *poly_bits_limit*. Returns 1 for success and 0 for failure. On failure, *G* is a valid basis for *F* but it might not be a Gröbner basis. Index pairs ------------------------------------------------------------------------------- .. type:: pair_t A pair of *slong* indices *a* and *b*. .. type:: pairs_struct .. type:: pairs_t A type holding a vector of :type:`pair_t`. .. function:: void pairs_init(pairs_t vec) Initializes *vec* for use, setting it to the empty vector of pairs. .. function:: void pairs_fit_length(pairs_t vec, slong len) Allocates space for *len* elements in *vec*. .. function:: void pairs_clear(pairs_t vec) Frees *vec*. .. function:: void pairs_append(pairs_t vec, slong i, slong j) Appends the pair `(i, j)` to the end of *vec*. .. function:: void pairs_insert_unique(pairs_t vec, slong i, slong j) Inserts `(i, j)` without duplication into *vec*. If this pair already exists, *vec* is unchanged. If this pair does not exist in *vec*, it is appended. .. raw:: latex \newpage calcium-0.4.1/examples/000077500000000000000000000000001407704557200147625ustar00rootroot00000000000000calcium-0.4.1/examples/binet.c000066400000000000000000000022611407704557200162300ustar00rootroot00000000000000/* This file is public domain. Author: Fredrik Johansson. */ #include "flint/profiler.h" #include "ca.h" int main(int argc, char *argv[]) { ca_ctx_t ctx; ca_t sqrt5, phi, psi, t, u; fmpz_t n; if (argc < 2) { flint_printf("usage: build/examples/binet [-limit B] n\n"); return 1; } fmpz_init(n); fmpz_set_str(n, argv[argc-1], 10); TIMEIT_ONCE_START ca_ctx_init(ctx); if (argc == 4) ctx->options[CA_OPT_PREC_LIMIT] = atol(argv[2]); ca_init(sqrt5, ctx); ca_init(phi, ctx); ca_init(psi, ctx); ca_init(t, ctx); ca_init(u, ctx); ca_sqrt_ui(sqrt5, 5, ctx); ca_add_ui(phi, sqrt5, 1, ctx); ca_div_ui(phi, phi, 2, ctx); ca_ui_sub(psi, 1, phi, ctx); ca_pow_fmpz(t, phi, n, ctx); ca_pow_fmpz(u, psi, n, ctx); ca_sub(t, t, u, ctx); ca_div(t, t, sqrt5, ctx); ca_print(t, ctx); flint_printf("\n"); ca_clear(sqrt5, ctx); ca_clear(phi, ctx); ca_clear(psi, ctx); ca_clear(t, ctx); ca_clear(u, ctx); ca_ctx_clear(ctx); fmpz_clear(n); flint_printf("\n"); TIMEIT_ONCE_STOP SHOW_MEMORY_USAGE flint_cleanup(); return EXIT_SUCCESS; } calcium-0.4.1/examples/dft.c000066400000000000000000000145701407704557200157120ustar00rootroot00000000000000/* This file is public domain. Author: Fredrik Johansson. */ #include "flint/profiler.h" #include "ca.h" #include "ca_vec.h" void benchmark_DFT(slong N, int input, int verbose, slong qqbar_limit, slong gb, ca_ctx_t ctx) { ca_ptr x, X, y, w; ca_t t; slong i, k, n; truth_t is_zero; x = _ca_vec_init(N, ctx); X = _ca_vec_init(N, ctx); y = _ca_vec_init(N, ctx); w = _ca_vec_init(2 * N, ctx); ca_init(t, ctx); /* ctx->options[CA_OPT_PRINT_FLAGS] = CA_PRINT_DEBUG; */ /* ctx->options[CA_OPT_VERBOSE] = 1; */ ctx->options[CA_OPT_USE_GROEBNER] = gb; if (qqbar_limit != 0) ctx->options[CA_OPT_QQBAR_DEG_LIMIT] = qqbar_limit; /* Construct input vector */ if (verbose) flint_printf("[x] =\n"); for (i = 0; i < N; i++) { if (input == 0) { ca_set_ui(x + i, i + 2, ctx); } else if (input == 1) { ca_set_ui(x + i, i + 2, ctx); ca_sqrt(x + i, x + i, ctx); } else if (input == 2) { ca_set_ui(x + i, i + 2, ctx); ca_log(x + i, x + i, ctx); } else if (input == 3) { ca_pi_i(x + i, ctx); ca_mul_ui(x + i, x + i, 2, ctx); ca_div_ui(x + i, x + i, i + 2, ctx); ca_exp(x + i, x + i, ctx); } else if (input == 4) { ca_pi(x + i, ctx); ca_mul_ui(x + i, x + i, i + 2, ctx); ca_add_ui(x + i, x + i, 1, ctx); ca_inv(x + i, x + i, ctx); } else if (input == 5) { ca_pi(x + i, ctx); ca_sqrt_ui(w, i + 2, ctx); ca_mul(x + i, x + i, w, ctx); ca_add_ui(x + i, x + i, 1, ctx); ca_inv(x + i, x + i, ctx); } if (verbose) { ca_print(x + i, ctx); printf("\n"); } } /* Construct roots of unity */ for (i = 0; i < 2 * N; i++) { if (i == 0) { ca_one(w + i, ctx); } else if (i == 1) { ca_pi_i(w + i, ctx); ca_mul_ui(w + i, w + i, 2, ctx); ca_div_si(w + i, w + i, N, ctx); ca_exp(w + i, w + i, ctx); } else { ca_mul(w + i, w + i - 1, w + 1, ctx); } } /* Forward DFT */ if (verbose) printf("\nDFT([x]) =\n"); for (k = 0; k < N; k++) { ca_zero(X + k, ctx); for (n = 0; n < N; n++) { ca_mul(t, x + n, w + ((2 * N - k) * n) % (2 * N), ctx); ca_add(X + k, X + k, t, ctx); } if (verbose) { ca_print(X + k, ctx); printf("\n"); } } /* Inverse DFT */ if (verbose) printf("\nIDFT(DFT([x])) =\n"); for (k = 0; k < N; k++) { ca_zero(y + k, ctx); for (n = 0; n < N; n++) { ca_mul(t, X + n, w + (k * n) % (2 * N), ctx); ca_add(y + k, y + k, t, ctx); } ca_div_ui(y + k, y + k, N, ctx); if (verbose) { ca_print(y + k, ctx); flint_printf("\n"); } } if (verbose) printf("\n[x] - IDFT(DFT([x])) =\n"); for (k = 0; k < N; k++) { ca_sub(t, x + k, y + k, ctx); is_zero = ca_check_is_zero(t, ctx); if (verbose) { ca_print(t, ctx); printf(" (= 0 "); truth_print(is_zero); printf(")\n"); } if (is_zero != T_TRUE) { printf("Failed to prove equality!\n"); flint_abort(); } } if (verbose) printf("\n"); _ca_vec_clear(x, N, ctx); _ca_vec_clear(X, N, ctx); _ca_vec_clear(y, N, ctx); _ca_vec_clear(w, 2 * N, ctx); ca_clear(t, ctx); } void usage() { printf("usage: dft [-verbose] [-input i] [-limit B] [-timing T] [-nogb] N\n"); } int main(int argc, char *argv[]) { ca_ctx_t ctx; int verbose, input, timing; slong i, Nmin, Nmax, N, qqbar_limit, gb; Nmin = Nmax = 2; verbose = 0; input = 0; timing = 0; qqbar_limit = 0; gb = 1; if (argc < 2) { usage(); return 1; } for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-verbose")) { verbose = 1; } else if (!strcmp(argv[i], "-input")) { input = atol(argv[i+1]); i += 1; } else if (!strcmp(argv[i], "-limit")) { qqbar_limit = atol(argv[i+1]); i += 1; } else if (!strcmp(argv[i], "-nogb")) { gb = 0; } else if (!strcmp(argv[i], "-timing")) { timing = atol(argv[i+1]); i += 1; } else { Nmin = Nmax = atol(argv[i]); if (Nmin < 0) { Nmin = 0; Nmax = -Nmax; } } } for (N = Nmin; N <= Nmax; N++) { flint_printf("DFT benchmark, length N = %wd\n", N); if (input == 0) flint_printf("x_k = k + 2\n"); else if (input == 1) flint_printf("x_k = sqrt(k + 2)\n"); else if (input == 2) flint_printf("x_k = log(k + 2)\n"); else if (input == 3) flint_printf("x_k = exp(2 pi i / (k + 2))\n"); else if (input == 4) flint_printf("x_k = 1 / (1 + (k + 2) pi)\n"); else if (input == 5) flint_printf("x_k = 1 / (1 + sqrt(k + 2) pi)\n"); flint_printf("\n"); if (timing == 0) { TIMEIT_ONCE_START ca_ctx_init(ctx); benchmark_DFT(N, input, verbose, qqbar_limit, gb, ctx); ca_ctx_clear(ctx); TIMEIT_ONCE_STOP } else if (timing == 1) { TIMEIT_START ca_ctx_init(ctx); benchmark_DFT(N, input, verbose, qqbar_limit, gb, ctx); ca_ctx_clear(ctx); TIMEIT_STOP } else { ca_ctx_init(ctx); benchmark_DFT(N, input, verbose, qqbar_limit, gb, ctx); TIMEIT_START benchmark_DFT(N, input, verbose, qqbar_limit, gb, ctx); TIMEIT_STOP ca_ctx_clear(ctx); } } SHOW_MEMORY_USAGE flint_cleanup(); return EXIT_SUCCESS; } calcium-0.4.1/examples/elementary.c000066400000000000000000000141351407704557200172770ustar00rootroot00000000000000/* This file is public domain. Author: Fredrik Johansson. */ #include "flint/profiler.h" #include "ca.h" #include "ca_ext.h" #include "ca_field.h" #define START(expr) flint_printf(">>> "); flint_printf(expr) #define OUT \ flint_printf("\n"); \ ca_print(x, ctx); flint_printf("\n\n"); #define OUT2 \ flint_printf("\n"); \ ca_print(x, ctx); flint_printf("\n"); \ flint_printf(">>> Is zero?\n"); truth_print(ca_check_is_zero(x, ctx)); \ flint_printf("\n\n"); void ca_set_qqi_si(ca_t res, slong a, slong b, slong c, slong d, ca_ctx_t ctx) { ca_t t; ca_init(t, ctx); ca_set_si(t, a, ctx); ca_div_si(t, t, b, ctx); ca_i(res, ctx); ca_mul_si(res, res, c, ctx); ca_div_si(res, res, d, ctx); ca_add(res, res, t, ctx); ca_clear(t, ctx); } int main(int argc, char *argv[]) { ca_ctx_t ctx; ca_t x, y, z; TIMEIT_ONCE_START ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(z, ctx); START("Exp(Pi*I) + 1"); ca_pi_i(x, ctx); ca_exp(x, x, ctx); ca_add_ui(x, x, 1, ctx); OUT START("Log(-1) / (Pi*I)"); ca_set_si(x, -1, ctx); ca_log(x, x, ctx); ca_pi_i(y, ctx); ca_div(x, x, y, ctx); OUT START("Log(-I) / (Pi*I)"); ca_neg_i(x, ctx); ca_log(x, x, ctx); ca_pi_i(y, ctx); ca_div(x, x, y, ctx); OUT START("Log(1 / 10^123) / Log(100)"); ca_set_ui(x, 10, ctx); ca_pow_ui(x, x, 123, ctx); ca_inv(x, x, ctx); ca_log(x, x, ctx); ca_set_ui(y, 100, ctx); ca_log(y, y, ctx); ca_div(x, x, y, ctx); OUT START("Log(1 + Sqrt(2)) / Log(3 + 2*Sqrt(2))"); ca_sqrt_ui(x, 2, ctx); ca_add_ui(x, x, 1, ctx); ca_log(x, x, ctx); ca_sqrt_ui(y, 2, ctx); ca_mul_ui(y, y, 2, ctx); ca_add_ui(y, y, 3, ctx); ca_log(y, y, ctx); ca_div(x, x, y, ctx); OUT START("Sqrt(2)*Sqrt(3) - Sqrt(6)"); ca_sqrt_ui(x, 2, ctx); ca_sqrt_ui(y, 3, ctx); ca_sqrt_ui(z, 6, ctx); ca_mul(x, x, y, ctx); ca_sub(x, x, z, ctx); OUT START("Exp(1+Sqrt(2)) * Exp(1-Sqrt(2)) / (Exp(1)^2)"); ca_sqrt_ui(x, 2, ctx); ca_add_ui(x, x, 1, ctx); ca_exp(x, x, ctx); ca_sqrt_ui(y, 2, ctx); ca_ui_sub(y, 1, y, ctx); ca_exp(y, y, ctx); ca_one(z, ctx); ca_exp(z, z, ctx); ca_pow_ui(z, z, 2, ctx); ca_mul(x, x, y, ctx); ca_div(x, x, z, ctx); OUT START("I^I - Exp(-Pi/2)"); ca_i(x, ctx); ca_pow(x, x, x, ctx); ca_pi(y, ctx); ca_div_ui(y, y, 2, ctx); ca_neg(y, y, ctx); ca_exp(y, y, ctx); ca_sub(x, x, y, ctx); OUT START("Exp(Sqrt(3))^2 - Exp(Sqrt(12))"); ca_sqrt_ui(x, 3, ctx); ca_exp(x, x, ctx); ca_pow_ui(x, x, 2, ctx); ca_sqrt_ui(y, 12, ctx); ca_exp(y, y, ctx); ca_sub(x, x, y, ctx); OUT START("2*Log(Pi*I) - 4*Log(Sqrt(Pi)) - Pi*I"); ca_pi_i(x, ctx); ca_log(x, x, ctx); ca_mul_ui(x, x, 2, ctx); ca_pi(y, ctx); ca_sqrt(y, y, ctx); ca_log(y, y, ctx); ca_mul_ui(y, y, 4, ctx); ca_sub(x, x, y, ctx); ca_pi_i(y, ctx); ca_sub(x, x, y, ctx); OUT /* Example 1 in [BBK2014] */ START("-I*Pi/8*Log(2/3-2*I/3)^2 + I*Pi/8*Log(2/3+2*I/3)^2 + Pi^2/12*Log(-1-I) + Pi^2/12*Log(-1+I) + Pi^2/12*Log(1/3-I/3) + Pi^2/12*Log(1/3+I/3) - Pi^2/48*Log(18)"); ca_zero(x, ctx); ca_set_qqi_si(y, 2, 3, -2, 3, ctx); ca_log(y, y, ctx); ca_sqr(y, y, ctx); ca_pi_i(z, ctx); ca_mul(y, y, z, ctx); ca_div_si(y, y, -8, ctx); ca_add(x, x, y, ctx); ca_set_qqi_si(y, 2, 3, 2, 3, ctx); ca_log(y, y, ctx); ca_sqr(y, y, ctx); ca_pi_i(z, ctx); ca_mul(y, y, z, ctx); ca_div_si(y, y, 8, ctx); ca_add(x, x, y, ctx); ca_set_qqi_si(y, -1, 1, -1, 1, ctx); ca_log(y, y, ctx); ca_pi(z, ctx); ca_sqr(z, z, ctx); ca_mul(y, y, z, ctx); ca_div_si(y, y, 12, ctx); ca_add(x, x, y, ctx); ca_set_qqi_si(y, -1, 1, 1, 1, ctx); ca_log(y, y, ctx); ca_pi(z, ctx); ca_sqr(z, z, ctx); ca_mul(y, y, z, ctx); ca_div_si(y, y, 12, ctx); ca_add(x, x, y, ctx); ca_set_qqi_si(y, 1, 3, -1, 3, ctx); ca_log(y, y, ctx); ca_pi(z, ctx); ca_sqr(z, z, ctx); ca_mul(y, y, z, ctx); ca_div_si(y, y, 12, ctx); ca_add(x, x, y, ctx); ca_set_qqi_si(y, 1, 3, 1, 3, ctx); ca_log(y, y, ctx); ca_pi(z, ctx); ca_sqr(z, z, ctx); ca_mul(y, y, z, ctx); ca_div_si(y, y, 12, ctx); ca_add(x, x, y, ctx); ca_set_ui(y, 18, ctx); ca_log(y, y, ctx); ca_pi(z, ctx); ca_sqr(z, z, ctx); ca_mul(y, y, z, ctx); ca_div_si(y, y, -48, ctx); ca_sub(x, x, y, ctx); OUT START("Sqrt(5 + 2*Sqrt(6)) - Sqrt(2) - Sqrt(3)"); ca_sqrt_ui(x, 6, ctx); ca_mul_ui(x, x, 2, ctx); ca_add_ui(x, x, 5, ctx); ca_sqrt(x, x, ctx); ca_sqrt_ui(y, 2, ctx); ca_sub(x, x, y, ctx); ca_sqrt_ui(y, 3, ctx); ca_sub(x, x, y, ctx); OUT2 START("Sqrt(I) - (1+I)/Sqrt(2)"); ca_i(x, ctx); ca_sqrt(x, x, ctx); ca_i(y, ctx); ca_add_ui(y, y, 1, ctx); ca_sqrt_ui(z, 2, ctx); ca_div(y, y, z, ctx); ca_sub(x, x, y, ctx); OUT2 START("Exp(Pi*Sqrt(163)) - (640320^3 + 744)"); ca_pi(x, ctx); ca_sqrt_ui(y, 163, ctx); ca_mul(x, x, y, ctx); ca_exp(x, x, ctx); ca_set_ui(y, 640320, ctx); ca_pow_ui(y, y, 3, ctx); ca_add_ui(y, y, 744, ctx); ca_sub(x, x, y, ctx); OUT /* Taken (slightly tweaked) from: https://reference.wolfram.com/language/ref/PossibleZeroQ.html */ START("Erf(2*Log(Sqrt(1/2-Sqrt(2)/4))+Log(4)) - Erf(Log(2-Sqrt(2)))"); ca_sqrt_ui(x, 2, ctx); ca_div_ui(x, x, 4, ctx); ca_one(y, ctx); ca_div_ui(y, y, 2, ctx); ca_sub(x, y, x, ctx); ca_sqrt(x, x, ctx); ca_log(x, x, ctx); ca_mul_ui(x, x, 2, ctx); ca_set_ui(y, 4, ctx); ca_log(y, y, ctx); ca_add(x, y, x, ctx); ca_erf(x, x, ctx); ca_sqrt_ui(y, 2, ctx); ca_ui_sub(y, 2, y, ctx); ca_log(y, y, ctx); ca_erf(y, y, ctx); ca_sub(x, x, y, ctx); OUT flint_printf("\n"); ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(z, ctx); ca_ctx_clear(ctx); TIMEIT_ONCE_STOP SHOW_MEMORY_USAGE flint_cleanup(); return EXIT_SUCCESS; } calcium-0.4.1/examples/hilbert_matrix.c000066400000000000000000000074041407704557200201500ustar00rootroot00000000000000/* This file is public domain. Author: Fredrik Johansson. */ #include "flint/profiler.h" #include "flint/fmpq_mat.h" #include "ca.h" #include "ca_vec.h" #include "ca_mat.h" #include "qqbar.h" int main(int argc, char *argv[]) { slong n, i; int qqbar, vieta, novieta; if (argc < 2) { flint_printf("usage: hilbert_matrix [-qqbar] [-vieta | -novieta] n\n"); return 1; } qqbar = 0; vieta = 0; novieta = 0; n = 0; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-qqbar")) { qqbar = 1; } else if (!strcmp(argv[i], "-vieta")) { vieta = 1; } else if (!strcmp(argv[i], "-novieta")) { novieta = 1; } else { n = atol(argv[i]); if (n < 0 || n > 100) flint_abort(); } } TIMEIT_ONCE_START if (qqbar) { fmpq_mat_t mat; qqbar_ptr eig; qqbar_t trace, det; fmpq_mat_init(mat, n, n); qqbar_init(trace); qqbar_init(det); eig = _qqbar_vec_init(n); fmpq_mat_hilbert_matrix(mat); qqbar_eigenvalues_fmpq_mat(eig, mat, 0); flint_printf("Trace:\n"); qqbar_zero(trace); for (i = 0; i < n; i++) { qqbar_add(trace, trace, eig + i); flint_printf("%wd/%wd: degree %wd\n", i, n, qqbar_degree(trace)); } qqbar_print(trace); flint_printf("\n"); flint_printf("Determinant:\n"); qqbar_one(det); for (i = 0; i < n; i++) { qqbar_mul(det, det, eig + i); flint_printf("%wd/%wd: degree %wd\n", i, n, qqbar_degree(det)); } qqbar_print(det); flint_printf("\n"); fmpq_mat_clear(mat); qqbar_clear(trace); qqbar_clear(det); _qqbar_vec_clear(eig, n); } else { ca_ctx_t ctx; ca_mat_t mat; ca_vec_t eig; ca_t trace, det, t; ulong * mul; ca_ctx_init(ctx); /* Verification requires high-degree algebraics. */ ctx->options[CA_OPT_QQBAR_DEG_LIMIT] = 10000; if (vieta) ctx->options[CA_OPT_VIETA_LIMIT] = n; if (novieta) ctx->options[CA_OPT_VIETA_LIMIT] = 0; ca_mat_init(mat, n, n, ctx); ca_vec_init(eig, 0, ctx); mul = flint_malloc(sizeof(ulong) * n); ca_init(trace, ctx); ca_init(det, ctx); ca_init(t, ctx); ca_mat_hilbert(mat, ctx); ca_mat_eigenvalues(eig, mul, mat, ctx); ca_mat_trace(trace, mat, ctx); ca_mat_det(det, mat, ctx); /* note: in general, we should use the multiplicities, but we happen to know that the eigenvalues are simple here */ flint_printf("Trace:\n"); ca_zero(t, ctx); for (i = 0; i < n; i++) ca_add(t, t, ca_vec_entry(eig, i), ctx); ca_print(trace, ctx); flint_printf("\n"); ca_print(t, ctx); flint_printf("\n"); flint_printf("Equal: "); truth_print(ca_check_equal(trace, t, ctx)); flint_printf("\n\n"); flint_printf("Det:\n"); ca_one(t, ctx); for (i = 0; i < n; i++) ca_mul(t, t, ca_vec_entry(eig, i), ctx); ca_print(det, ctx); flint_printf("\n"); ca_print(t, ctx); flint_printf("\n"); flint_printf("Equal: "); truth_print(ca_check_equal(det, t, ctx)); flint_printf("\n\n"); ca_mat_clear(mat, ctx); ca_vec_clear(eig, ctx); flint_free(mul); ca_clear(trace, ctx); ca_clear(det, ctx); ca_clear(t, ctx); ca_ctx_clear(ctx); } flint_printf("\n"); TIMEIT_ONCE_STOP SHOW_MEMORY_USAGE flint_cleanup(); return EXIT_SUCCESS; } calcium-0.4.1/examples/huge_expr.c000066400000000000000000017040231407704557200171230ustar00rootroot00000000000000/* This file is public domain. Author: Fredrik Johansson. */ #include "flint/profiler.h" #include "ca.h" #include "ca_ext.h" #include "ca_field.h" void main_ca() { ca_ctx_t ctx; ca_t N, M, E; ca_t tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17, tmp18, tmp19, tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27, tmp28, tmp29, tmp30, tmp31, tmp32, tmp33, tmp34; truth_t equal; ca_ctx_init(ctx); ca_init(N, ctx); ca_init(M, ctx); ca_init(E, ctx); ca_init(tmp0, ctx); ca_init(tmp1, ctx); ca_init(tmp2, ctx); ca_init(tmp3, ctx); ca_init(tmp4, ctx); ca_init(tmp5, ctx); ca_init(tmp6, ctx); ca_init(tmp7, ctx); ca_init(tmp8, ctx); ca_init(tmp9, ctx); ca_init(tmp10, ctx); ca_init(tmp11, ctx); ca_init(tmp12, ctx); ca_init(tmp13, ctx); ca_init(tmp14, ctx); ca_init(tmp15, ctx); ca_init(tmp16, ctx); ca_init(tmp17, ctx); ca_init(tmp18, ctx); ca_init(tmp19, ctx); ca_init(tmp20, ctx); ca_init(tmp21, ctx); ca_init(tmp22, ctx); ca_init(tmp23, ctx); ca_init(tmp24, ctx); ca_init(tmp25, ctx); ca_init(tmp26, ctx); ca_init(tmp27, ctx); ca_init(tmp28, ctx); ca_init(tmp29, ctx); ca_init(tmp30, ctx); ca_init(tmp31, ctx); ca_init(tmp32, ctx); ca_init(tmp33, ctx); ca_init(tmp34, ctx); flint_printf("Evaluating N...\n"); TIMEIT_ONCE_START ca_set_si(tmp3, 1, ctx); ca_div_si(tmp3, tmp3, 16, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, 7, ctx); ca_sub_si(tmp11, tmp11, 10, ctx); ca_mul_si(tmp11, tmp11, 44, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_add_si(tmp12, tmp12, 2, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, -17, ctx); ca_add_si(tmp11, tmp11, 26, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 7, ctx); ca_sub_si(tmp16, tmp16, 10, ctx); ca_mul_si(tmp16, tmp16, 11, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, -17, ctx); ca_add_si(tmp16, tmp16, 26, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 63, ctx); ca_sub_si(tmp16, tmp16, 89, ctx); ca_mul_si(tmp16, tmp16, 10, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sub(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 3, ctx); ca_sub_si(tmp18, tmp18, 4, ctx); ca_mul_si(tmp18, tmp18, 3, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, -17, ctx); ca_add_si(tmp18, tmp18, 26, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 85, ctx); ca_sub_si(tmp18, tmp18, 122, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_neg(tmp16, tmp16, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sub(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 3, ctx); ca_sub_si(tmp19, tmp19, 4, ctx); ca_mul_si(tmp19, tmp19, 3, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 85, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 122, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_neg(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 7, ctx); ca_sub_si(tmp18, tmp18, 10, ctx); ca_mul_si(tmp18, tmp18, 11, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 630, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sub_si(tmp14, tmp14, 890, ctx); ca_mul_si(tmp14, tmp14, 2, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_sub_si(tmp15, tmp15, 1, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_add(tmp11, tmp12, tmp13, ctx); ca_mul_si(tmp11, tmp11, 2, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, 3, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, -17, ctx); ca_add_si(tmp14, tmp14, 26, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_add(tmp12, tmp13, tmp14, ctx); ca_sub_si(tmp12, tmp12, 3, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_add(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 63, ctx); ca_sub_si(tmp10, tmp10, 89, ctx); ca_mul_si(tmp10, tmp10, 40, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_sub(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, 3, ctx); ca_sub_si(tmp12, tmp12, 4, ctx); ca_mul_si(tmp12, tmp12, 3, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, -17, ctx); ca_add_si(tmp12, tmp12, 26, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, 85, ctx); ca_sub_si(tmp12, tmp12, 122, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sub(tmp9, tmp10, tmp11, ctx); ca_mul_si(tmp9, tmp9, 4, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_neg(tmp10, tmp10, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_sub(tmp6, tmp7, tmp8, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 5, ctx); ca_sub_si(tmp14, tmp14, 7, ctx); ca_mul_si(tmp14, tmp14, 22, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, -17, ctx); ca_add_si(tmp14, tmp14, 26, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 5, ctx); ca_sub_si(tmp19, tmp19, 7, ctx); ca_mul_si(tmp19, tmp19, 11, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 89, ctx); ca_sub_si(tmp19, tmp19, 126, ctx); ca_mul_si(tmp19, tmp19, 5, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 2, ctx); ca_sub_si(tmp21, tmp21, 3, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 61, ctx); ca_sub_si(tmp21, tmp21, 85, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_neg(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 2, ctx); ca_sub_si(tmp22, tmp22, 3, ctx); ca_mul_si(tmp22, tmp22, 3, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 61, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 85, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_neg(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 5, ctx); ca_sub_si(tmp21, tmp21, 7, ctx); ca_mul_si(tmp21, tmp21, 11, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 445, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sub_si(tmp17, tmp17, 630, ctx); ca_mul_si(tmp17, tmp17, 2, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_sub_si(tmp18, tmp18, 1, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 3, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, -17, ctx); ca_add_si(tmp17, tmp17, 26, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sub_si(tmp15, tmp15, 3, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_add(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, 89, ctx); ca_sub_si(tmp13, tmp13, 126, ctx); ca_mul_si(tmp13, tmp13, 10, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 2, ctx); ca_sub_si(tmp15, tmp15, 3, ctx); ca_mul_si(tmp15, tmp15, 3, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, -17, ctx); ca_add_si(tmp15, tmp15, 26, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 61, ctx); ca_sub_si(tmp15, tmp15, 85, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sub(tmp12, tmp13, tmp14, ctx); ca_mul_si(tmp12, tmp12, 2, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_neg(tmp13, tmp13, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sub(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 2, ctx); ca_sub_si(tmp16, tmp16, 3, ctx); ca_mul_si(tmp16, tmp16, 3, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, -17, ctx); ca_add_si(tmp17, tmp17, 26, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 61, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_add_si(tmp14, tmp14, 85, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_neg(tmp15, tmp15, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 5, ctx); ca_sub_si(tmp15, tmp15, 7, ctx); ca_mul_si(tmp15, tmp15, 11, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, -17, ctx); ca_add_si(tmp16, tmp16, 26, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sub(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, 445, ctx); ca_add(tmp11, tmp12, tmp13, ctx); ca_sub_si(tmp11, tmp11, 630, ctx); ca_mul_si(tmp11, tmp11, 4, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_add_si(tmp12, tmp12, 2, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_sub_si(tmp12, tmp12, 1, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_add(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, -12, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_neg(tmp12, tmp12, ctx); ca_add_si(tmp12, tmp12, 2, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul_si(tmp12, tmp12, 2, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, -17, ctx); ca_add_si(tmp11, tmp11, 26, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul_si(tmp11, tmp11, 2, ctx); ca_sub(tmp9, tmp10, tmp11, ctx); ca_add_si(tmp9, tmp9, 24, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_add(tmp5, tmp6, tmp7, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, 3, ctx); ca_sub_si(tmp12, tmp12, 4, ctx); ca_mul_si(tmp12, tmp12, 3, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, -17, ctx); ca_add_si(tmp13, tmp13, 26, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, 85, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_add_si(tmp10, tmp10, 122, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_neg(tmp11, tmp11, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, 7, ctx); ca_sub_si(tmp11, tmp11, 10, ctx); ca_mul_si(tmp11, tmp11, 11, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, -17, ctx); ca_add_si(tmp12, tmp12, 26, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_mul_si(tmp9, tmp9, 630, ctx); ca_add(tmp7, tmp8, tmp9, ctx); ca_sub_si(tmp7, tmp7, 890, ctx); ca_mul_si(tmp7, tmp7, 8, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_add_si(tmp8, tmp8, 2, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_sub_si(tmp8, tmp8, 1, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_add(tmp4, tmp5, tmp6, ctx); ca_mul(tmp2, tmp3, tmp4, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_add_si(tmp12, tmp12, 2, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_sub(tmp9, tmp10, tmp11, ctx); ca_sub_si(tmp9, tmp9, 1, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_sub_si(tmp10, tmp10, 1, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_add_si(tmp9, tmp9, 2, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_add(tmp7, tmp8, tmp9, ctx); ca_sub_si(tmp7, tmp7, 1, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 89, ctx); ca_sub_si(tmp18, tmp18, 126, ctx); ca_mul_si(tmp18, tmp18, 5, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 61, ctx); ca_sub_si(tmp22, tmp22, 85, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 2, ctx); ca_sub_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 4, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_add_si(tmp23, tmp23, 6, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 122, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_add_si(tmp19, tmp19, 170, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_neg(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 5, ctx); ca_sub_si(tmp20, tmp20, 7, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 10, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 14, ctx); ca_mul_si(tmp18, tmp18, 11, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 890, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_add_si(tmp14, tmp14, 1260, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 3, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_neg(tmp17, tmp17, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sub_si(tmp15, tmp15, 5, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, -12, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_neg(tmp17, tmp17, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul_si(tmp17, tmp17, 2, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, -17, ctx); ca_add_si(tmp16, tmp16, 26, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul_si(tmp16, tmp16, 2, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_add_si(tmp14, tmp14, 24, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 63, ctx); ca_sub_si(tmp18, tmp18, 89, ctx); ca_mul_si(tmp18, tmp18, 10, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 85, ctx); ca_sub_si(tmp22, tmp22, 122, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sub_si(tmp25, tmp25, 4, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 6, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_add_si(tmp23, tmp23, 8, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 170, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_add_si(tmp19, tmp19, 244, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_neg(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 7, ctx); ca_sub_si(tmp20, tmp20, 10, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 14, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 20, ctx); ca_mul_si(tmp18, tmp18, 11, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 1260, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_add_si(tmp14, tmp14, 1780, ctx); ca_mul_si(tmp14, tmp14, 2, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 3, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_neg(tmp17, tmp17, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sub_si(tmp15, tmp15, 5, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_add(tmp11, tmp12, tmp13, ctx); ca_mul_si(tmp11, tmp11, 8, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_add_si(tmp15, tmp15, 1, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_sub_si(tmp16, tmp16, 1, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_add_si(tmp13, tmp13, 1, ctx); ca_si_div(tmp13, 1, tmp13, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_sub_si(tmp21, tmp21, 1, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 3, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul_si(tmp19, tmp19, 5, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 8, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul_si(tmp20, tmp20, 5, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sub_si(tmp18, tmp18, 8, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 1, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_sub_si(tmp21, tmp21, 1, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 1, ctx); ca_pow_ui(tmp18, tmp18, 2, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 1, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub_si(tmp23, tmp23, 1, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_add(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_sub_si(tmp28, tmp28, 1, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_add(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul_si(tmp26, tmp26, 5, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_add_si(tmp24, tmp24, 8, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_add(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_sub_si(tmp29, tmp29, 1, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_add(tmp25, tmp26, tmp27, ctx); ca_sub_si(tmp25, tmp25, 8, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add_si(tmp26, tmp26, 1, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_sub_si(tmp27, tmp27, 1, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_add_si(tmp24, tmp24, 1, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_sub_si(tmp25, tmp25, 2, ctx); ca_pow_ui(tmp25, tmp25, 3, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_div(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sub_si(tmp19, tmp19, 1, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_sub_si(tmp18, tmp18, 2, ctx); ca_pow_ui(tmp18, tmp18, 3, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_div(tmp14, tmp15, tmp16, ctx); ca_add(tmp12, tmp13, tmp14, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_sub_si(tmp23, tmp23, 4, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 85, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 122, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_neg(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 7, ctx); ca_sub_si(tmp22, tmp22, 10, ctx); ca_mul_si(tmp22, tmp22, 11, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 630, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sub_si(tmp18, tmp18, 890, ctx); ca_mul_si(tmp18, tmp18, 2, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 3, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sub_si(tmp19, tmp19, 3, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_sub_si(tmp18, tmp18, 1, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 4896, ctx); ca_sub_si(tmp18, tmp18, 6923, ctx); ca_mul_si(tmp18, tmp18, 2, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 79, ctx); ca_sub_si(tmp20, tmp20, 112, ctx); ca_mul_si(tmp20, tmp20, 20, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 27, ctx); ca_sub_si(tmp23, tmp23, 38, ctx); ca_mul_si(tmp23, tmp23, 7, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 342, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 484, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 2820, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 3992, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_neg(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 2, ctx); ca_sub_si(tmp27, tmp27, 3, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 61, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 85, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_neg(tmp26, tmp26, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 5, ctx); ca_sub_si(tmp26, tmp26, 7, ctx); ca_mul_si(tmp26, tmp26, 11, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 445, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sub_si(tmp22, tmp22, 630, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sub_si(tmp23, tmp23, 3, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 89, ctx); ca_sub_si(tmp22, tmp22, 126, ctx); ca_mul_si(tmp22, tmp22, 10, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 61, ctx); ca_sub_si(tmp24, tmp24, 85, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 2, ctx); ca_sub_si(tmp27, tmp27, 3, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 2, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 3, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 61, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 85, ctx); ca_mul_si(tmp21, tmp21, 2, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_neg(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 5, ctx); ca_sub_si(tmp22, tmp22, 7, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 5, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 7, ctx); ca_mul_si(tmp20, tmp20, 22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 890, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_sub_si(tmp16, tmp16, 1260, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -12, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_neg(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul_si(tmp20, tmp20, 2, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 24, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 319, ctx); ca_sub_si(tmp17, tmp17, 452, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 561, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_add_si(tmp15, tmp15, 794, ctx); ca_mul_si(tmp15, tmp15, 4, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, -17, ctx); ca_add_si(tmp16, tmp16, 26, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_add(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, 17064, ctx); ca_add(tmp11, tmp12, tmp13, ctx); ca_sub_si(tmp11, tmp11, 24132, ctx); ca_div(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 7, ctx); ca_sub_si(tmp20, tmp20, 10, ctx); ca_mul_si(tmp20, tmp20, 44, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 7, ctx); ca_sub_si(tmp25, tmp25, 10, ctx); ca_mul_si(tmp25, tmp25, 11, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 63, ctx); ca_sub_si(tmp25, tmp25, 89, ctx); ca_mul_si(tmp25, tmp25, 10, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_sub_si(tmp27, tmp27, 4, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 85, ctx); ca_sub_si(tmp27, tmp27, 122, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_neg(tmp25, tmp25, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sub_si(tmp28, tmp28, 4, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, -17, ctx); ca_add_si(tmp29, tmp29, 26, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 85, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 122, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_neg(tmp27, tmp27, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 7, ctx); ca_sub_si(tmp27, tmp27, 10, ctx); ca_mul_si(tmp27, tmp27, 11, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 630, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sub_si(tmp23, tmp23, 890, ctx); ca_mul_si(tmp23, tmp23, 2, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_sub_si(tmp24, tmp24, 1, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_mul_si(tmp20, tmp20, 2, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 3, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sub_si(tmp21, tmp21, 3, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 63, ctx); ca_sub_si(tmp19, tmp19, 89, ctx); ca_mul_si(tmp19, tmp19, 40, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_sub_si(tmp21, tmp21, 4, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 85, ctx); ca_sub_si(tmp21, tmp21, 122, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_mul_si(tmp18, tmp18, 4, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_neg(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 5, ctx); ca_sub_si(tmp23, tmp23, 7, ctx); ca_mul_si(tmp23, tmp23, 22, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 5, ctx); ca_sub_si(tmp28, tmp28, 7, ctx); ca_mul_si(tmp28, tmp28, 11, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 89, ctx); ca_sub_si(tmp28, tmp28, 126, ctx); ca_mul_si(tmp28, tmp28, 5, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, 2, ctx); ca_sub_si(tmp30, tmp30, 3, ctx); ca_mul_si(tmp30, tmp30, 3, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_add_si(tmp31, tmp31, 2, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, -17, ctx); ca_add_si(tmp30, tmp30, 26, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, 61, ctx); ca_sub_si(tmp30, tmp30, 85, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_add_si(tmp31, tmp31, 2, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sub(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_neg(tmp28, tmp28, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 2, ctx); ca_sub_si(tmp31, tmp31, 3, ctx); ca_mul_si(tmp31, tmp31, 3, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, -17, ctx); ca_add_si(tmp32, tmp32, 26, ctx); ca_sqrt(tmp32, tmp32, ctx); ca_mul(tmp30, tmp31, tmp32, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 61, ctx); ca_sub(tmp29, tmp30, tmp31, ctx); ca_add_si(tmp29, tmp29, 85, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_neg(tmp30, tmp30, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, 5, ctx); ca_sub_si(tmp30, tmp30, 7, ctx); ca_mul_si(tmp30, tmp30, 11, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, -17, ctx); ca_add_si(tmp31, tmp31, 26, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sub(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 445, ctx); ca_add(tmp26, tmp27, tmp28, ctx); ca_sub_si(tmp26, tmp26, 630, ctx); ca_mul_si(tmp26, tmp26, 2, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_sub_si(tmp27, tmp27, 1, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sub_si(tmp24, tmp24, 3, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 89, ctx); ca_sub_si(tmp22, tmp22, 126, ctx); ca_mul_si(tmp22, tmp22, 10, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 2, ctx); ca_sub_si(tmp24, tmp24, 3, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 61, ctx); ca_sub_si(tmp24, tmp24, 85, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_mul_si(tmp21, tmp21, 2, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_neg(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 2, ctx); ca_sub_si(tmp25, tmp25, 3, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 61, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_add_si(tmp23, tmp23, 85, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_neg(tmp24, tmp24, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 5, ctx); ca_sub_si(tmp24, tmp24, 7, ctx); ca_mul_si(tmp24, tmp24, 11, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 445, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_sub_si(tmp20, tmp20, 630, ctx); ca_mul_si(tmp20, tmp20, 4, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_sub_si(tmp21, tmp21, 1, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -12, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_neg(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul_si(tmp21, tmp21, 2, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul_si(tmp20, tmp20, 2, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 24, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_sub_si(tmp21, tmp21, 4, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 85, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_add_si(tmp19, tmp19, 122, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_neg(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 7, ctx); ca_sub_si(tmp20, tmp20, 10, ctx); ca_mul_si(tmp20, tmp20, 11, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 630, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_sub_si(tmp16, tmp16, 890, ctx); ca_mul_si(tmp16, tmp16, 8, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_sub_si(tmp17, tmp17, 1, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_sub_si(tmp18, tmp18, 1, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 3, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul_si(tmp16, tmp16, 5, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_add_si(tmp14, tmp14, 8, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_sub_si(tmp27, tmp27, 4, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 85, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 122, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_neg(tmp26, tmp26, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 7, ctx); ca_sub_si(tmp26, tmp26, 10, ctx); ca_mul_si(tmp26, tmp26, 11, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 630, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sub_si(tmp22, tmp22, 890, ctx); ca_mul_si(tmp22, tmp22, 2, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sub_si(tmp23, tmp23, 3, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 4896, ctx); ca_sub_si(tmp22, tmp22, 6923, ctx); ca_mul_si(tmp22, tmp22, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 79, ctx); ca_sub_si(tmp24, tmp24, 112, ctx); ca_mul_si(tmp24, tmp24, 20, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 27, ctx); ca_sub_si(tmp27, tmp27, 38, ctx); ca_mul_si(tmp27, tmp27, 7, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 342, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 484, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 2820, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 3992, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_neg(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 2, ctx); ca_sub_si(tmp31, tmp31, 3, ctx); ca_mul_si(tmp31, tmp31, 3, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, -17, ctx); ca_add_si(tmp32, tmp32, 26, ctx); ca_sqrt(tmp32, tmp32, ctx); ca_mul(tmp30, tmp31, tmp32, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 61, ctx); ca_sub(tmp29, tmp30, tmp31, ctx); ca_add_si(tmp29, tmp29, 85, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_neg(tmp30, tmp30, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, 5, ctx); ca_sub_si(tmp30, tmp30, 7, ctx); ca_mul_si(tmp30, tmp30, 11, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, -17, ctx); ca_add_si(tmp31, tmp31, 26, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sub(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 445, ctx); ca_add(tmp26, tmp27, tmp28, ctx); ca_sub_si(tmp26, tmp26, 630, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, -17, ctx); ca_add_si(tmp29, tmp29, 26, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_add(tmp27, tmp28, tmp29, ctx); ca_sub_si(tmp27, tmp27, 3, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_sub_si(tmp26, tmp26, 1, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 89, ctx); ca_sub_si(tmp26, tmp26, 126, ctx); ca_mul_si(tmp26, tmp26, 10, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 61, ctx); ca_sub_si(tmp28, tmp28, 85, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 2, ctx); ca_sub_si(tmp31, tmp31, 3, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_add_si(tmp32, tmp32, 2, ctx); ca_sqrt(tmp32, tmp32, ctx); ca_mul(tmp30, tmp31, tmp32, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 2, ctx); ca_sub(tmp29, tmp30, tmp31, ctx); ca_add_si(tmp29, tmp29, 3, ctx); ca_mul_si(tmp29, tmp29, 3, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, -17, ctx); ca_add_si(tmp30, tmp30, 26, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 61, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 85, ctx); ca_mul_si(tmp25, tmp25, 2, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_neg(tmp26, tmp26, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 5, ctx); ca_sub_si(tmp26, tmp26, 7, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 5, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_add_si(tmp24, tmp24, 7, ctx); ca_mul_si(tmp24, tmp24, 22, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 890, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_sub_si(tmp20, tmp20, 1260, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -12, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_neg(tmp24, tmp24, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul_si(tmp24, tmp24, 2, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul_si(tmp23, tmp23, 2, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 24, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 319, ctx); ca_sub_si(tmp21, tmp21, 452, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 561, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_add_si(tmp19, tmp19, 794, ctx); ca_mul_si(tmp19, tmp19, 4, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 17064, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sub_si(tmp15, tmp15, 24132, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 1, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub_si(tmp19, tmp19, 1, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_add_si(tmp16, tmp16, 1, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 1, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub_si(tmp19, tmp19, 1, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_sub_si(tmp24, tmp24, 1, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul_si(tmp22, tmp22, 5, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 8, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_sub_si(tmp25, tmp25, 1, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul_si(tmp23, tmp23, 5, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sub_si(tmp21, tmp21, 8, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 1, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub_si(tmp23, tmp23, 1, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 1, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_sub_si(tmp21, tmp21, 2, ctx); ca_pow_ui(tmp21, tmp21, 3, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_div(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sub_si(tmp15, tmp15, 1, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_set_si(tmp17, 1, ctx); ca_div_si(tmp17, tmp17, 4, ctx); ca_neg(tmp17, tmp17, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_set_si(tmp17, 1, ctx); ca_div_si(tmp17, tmp17, 2, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_set_si(tmp16, 3, ctx); ca_div_si(tmp16, tmp16, 2, ctx); ca_pow(tmp14, tmp15, tmp16, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_div(tmp10, tmp11, tmp12, ctx); ca_add(tmp8, tmp9, tmp10, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_sqrt_ui(tmp7, 2, ctx); ca_add_si(tmp7, tmp7, 2, ctx); ca_sqrt(tmp7, tmp7, ctx); ca_add_si(tmp7, tmp7, 2, ctx); ca_sqrt(tmp7, tmp7, ctx); ca_mul(tmp5, tmp6, tmp7, ctx); ca_set_si(tmp8, 1, ctx); ca_div_si(tmp8, tmp8, 4, ctx); ca_neg(tmp8, tmp8, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_add_si(tmp9, tmp9, 2, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_set_si(tmp8, 1, ctx); ca_div_si(tmp8, tmp8, 2, ctx); ca_add(tmp6, tmp7, tmp8, ctx); ca_sqrt(tmp6, tmp6, ctx); ca_div(tmp4, tmp5, tmp6, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_sub_si(tmp12, tmp12, 1, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_sub_si(tmp11, tmp11, 1, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_add_si(tmp9, tmp9, 2, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_add(tmp7, tmp8, tmp9, ctx); ca_mul_si(tmp7, tmp7, 2, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 7, ctx); ca_sub_si(tmp18, tmp18, 10, ctx); ca_mul_si(tmp18, tmp18, 44, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, -17, ctx); ca_add_si(tmp18, tmp18, 26, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 7, ctx); ca_sub_si(tmp23, tmp23, 10, ctx); ca_mul_si(tmp23, tmp23, 11, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 63, ctx); ca_sub_si(tmp23, tmp23, 89, ctx); ca_mul_si(tmp23, tmp23, 10, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sub_si(tmp25, tmp25, 4, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 85, ctx); ca_sub_si(tmp25, tmp25, 122, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_neg(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 3, ctx); ca_sub_si(tmp26, tmp26, 4, ctx); ca_mul_si(tmp26, tmp26, 3, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 85, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_add_si(tmp24, tmp24, 122, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_neg(tmp25, tmp25, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 7, ctx); ca_sub_si(tmp25, tmp25, 10, ctx); ca_mul_si(tmp25, tmp25, 11, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 630, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sub_si(tmp21, tmp21, 890, ctx); ca_mul_si(tmp21, tmp21, 2, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_mul_si(tmp18, tmp18, 2, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 3, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sub_si(tmp19, tmp19, 3, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 63, ctx); ca_sub_si(tmp17, tmp17, 89, ctx); ca_mul_si(tmp17, tmp17, 40, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 3, ctx); ca_sub_si(tmp19, tmp19, 4, ctx); ca_mul_si(tmp19, tmp19, 3, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 85, ctx); ca_sub_si(tmp19, tmp19, 122, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_mul_si(tmp16, tmp16, 4, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_neg(tmp17, tmp17, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sub(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 5, ctx); ca_sub_si(tmp21, tmp21, 7, ctx); ca_mul_si(tmp21, tmp21, 22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 5, ctx); ca_sub_si(tmp26, tmp26, 7, ctx); ca_mul_si(tmp26, tmp26, 11, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 89, ctx); ca_sub_si(tmp26, tmp26, 126, ctx); ca_mul_si(tmp26, tmp26, 5, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 2, ctx); ca_sub_si(tmp28, tmp28, 3, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 61, ctx); ca_sub_si(tmp28, tmp28, 85, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_neg(tmp26, tmp26, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 2, ctx); ca_sub_si(tmp29, tmp29, 3, ctx); ca_mul_si(tmp29, tmp29, 3, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, -17, ctx); ca_add_si(tmp30, tmp30, 26, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 61, ctx); ca_sub(tmp27, tmp28, tmp29, ctx); ca_add_si(tmp27, tmp27, 85, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_neg(tmp28, tmp28, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 5, ctx); ca_sub_si(tmp28, tmp28, 7, ctx); ca_mul_si(tmp28, tmp28, 11, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, -17, ctx); ca_add_si(tmp29, tmp29, 26, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 445, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sub_si(tmp24, tmp24, 630, ctx); ca_mul_si(tmp24, tmp24, 2, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_sub_si(tmp25, tmp25, 1, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sub_si(tmp22, tmp22, 3, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 89, ctx); ca_sub_si(tmp20, tmp20, 126, ctx); ca_mul_si(tmp20, tmp20, 10, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 2, ctx); ca_sub_si(tmp22, tmp22, 3, ctx); ca_mul_si(tmp22, tmp22, 3, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 61, ctx); ca_sub_si(tmp22, tmp22, 85, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_neg(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 2, ctx); ca_sub_si(tmp23, tmp23, 3, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 61, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 85, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_neg(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 5, ctx); ca_sub_si(tmp22, tmp22, 7, ctx); ca_mul_si(tmp22, tmp22, 11, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 445, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sub_si(tmp18, tmp18, 630, ctx); ca_mul_si(tmp18, tmp18, 4, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub_si(tmp19, tmp19, 1, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, -12, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_neg(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, -17, ctx); ca_add_si(tmp18, tmp18, 26, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul_si(tmp18, tmp18, 2, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_add_si(tmp16, tmp16, 24, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_add(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 3, ctx); ca_sub_si(tmp19, tmp19, 4, ctx); ca_mul_si(tmp19, tmp19, 3, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 85, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 122, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_neg(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 7, ctx); ca_sub_si(tmp18, tmp18, 10, ctx); ca_mul_si(tmp18, tmp18, 11, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 630, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sub_si(tmp14, tmp14, 890, ctx); ca_mul_si(tmp14, tmp14, 8, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_sub_si(tmp15, tmp15, 1, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sub(tmp11, tmp12, tmp13, ctx); ca_mul_si(tmp11, tmp11, 8, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_add_si(tmp15, tmp15, 1, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_sub_si(tmp16, tmp16, 1, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_add_si(tmp13, tmp13, 1, ctx); ca_si_div(tmp13, 1, tmp13, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_sub_si(tmp21, tmp21, 1, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 3, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul_si(tmp19, tmp19, 5, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 8, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul_si(tmp20, tmp20, 5, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sub_si(tmp18, tmp18, 8, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 1, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_sub_si(tmp21, tmp21, 1, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 1, ctx); ca_pow_ui(tmp18, tmp18, 2, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 1, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub_si(tmp23, tmp23, 1, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_add(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_sub_si(tmp28, tmp28, 1, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_add(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul_si(tmp26, tmp26, 5, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_add_si(tmp24, tmp24, 8, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_add(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_sub_si(tmp29, tmp29, 1, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_add(tmp25, tmp26, tmp27, ctx); ca_sub_si(tmp25, tmp25, 8, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add_si(tmp26, tmp26, 1, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_sub_si(tmp27, tmp27, 1, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_add_si(tmp24, tmp24, 1, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_sub_si(tmp25, tmp25, 2, ctx); ca_pow_ui(tmp25, tmp25, 3, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_div(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sub_si(tmp19, tmp19, 1, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_sub_si(tmp18, tmp18, 2, ctx); ca_pow_ui(tmp18, tmp18, 3, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_div(tmp14, tmp15, tmp16, ctx); ca_add(tmp12, tmp13, tmp14, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_sub_si(tmp23, tmp23, 4, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 85, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 122, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_neg(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 7, ctx); ca_sub_si(tmp22, tmp22, 10, ctx); ca_mul_si(tmp22, tmp22, 11, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 630, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sub_si(tmp18, tmp18, 890, ctx); ca_mul_si(tmp18, tmp18, 2, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 3, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sub_si(tmp19, tmp19, 3, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_sub_si(tmp18, tmp18, 1, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 4896, ctx); ca_sub_si(tmp18, tmp18, 6923, ctx); ca_mul_si(tmp18, tmp18, 2, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 79, ctx); ca_sub_si(tmp20, tmp20, 112, ctx); ca_mul_si(tmp20, tmp20, 20, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 27, ctx); ca_sub_si(tmp23, tmp23, 38, ctx); ca_mul_si(tmp23, tmp23, 7, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 342, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 484, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 2820, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 3992, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_neg(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 2, ctx); ca_sub_si(tmp27, tmp27, 3, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 61, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 85, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_neg(tmp26, tmp26, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 5, ctx); ca_sub_si(tmp26, tmp26, 7, ctx); ca_mul_si(tmp26, tmp26, 11, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 445, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sub_si(tmp22, tmp22, 630, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sub_si(tmp23, tmp23, 3, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 89, ctx); ca_sub_si(tmp22, tmp22, 126, ctx); ca_mul_si(tmp22, tmp22, 10, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 61, ctx); ca_sub_si(tmp24, tmp24, 85, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 2, ctx); ca_sub_si(tmp27, tmp27, 3, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 2, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 3, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 61, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 85, ctx); ca_mul_si(tmp21, tmp21, 2, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_neg(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 5, ctx); ca_sub_si(tmp22, tmp22, 7, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 5, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 7, ctx); ca_mul_si(tmp20, tmp20, 22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 890, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_sub_si(tmp16, tmp16, 1260, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -12, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_neg(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul_si(tmp20, tmp20, 2, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 24, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 319, ctx); ca_sub_si(tmp17, tmp17, 452, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 561, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_add_si(tmp15, tmp15, 794, ctx); ca_mul_si(tmp15, tmp15, 4, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, -17, ctx); ca_add_si(tmp16, tmp16, 26, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_add(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, 17064, ctx); ca_add(tmp11, tmp12, tmp13, ctx); ca_sub_si(tmp11, tmp11, 24132, ctx); ca_div(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 89, ctx); ca_sub_si(tmp20, tmp20, 126, ctx); ca_mul_si(tmp20, tmp20, 5, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 61, ctx); ca_sub_si(tmp24, tmp24, 85, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 2, ctx); ca_sub_si(tmp27, tmp27, 3, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 4, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 6, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 122, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 170, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_neg(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 5, ctx); ca_sub_si(tmp22, tmp22, 7, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 10, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 14, ctx); ca_mul_si(tmp20, tmp20, 11, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 890, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_add_si(tmp16, tmp16, 1260, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 3, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_neg(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sub_si(tmp17, tmp17, 5, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, -12, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_neg(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, -17, ctx); ca_add_si(tmp18, tmp18, 26, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul_si(tmp18, tmp18, 2, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_add_si(tmp16, tmp16, 24, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 63, ctx); ca_sub_si(tmp20, tmp20, 89, ctx); ca_mul_si(tmp20, tmp20, 10, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 85, ctx); ca_sub_si(tmp24, tmp24, 122, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_sub_si(tmp27, tmp27, 4, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 6, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 8, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 170, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 244, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_neg(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 7, ctx); ca_sub_si(tmp22, tmp22, 10, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 14, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 20, ctx); ca_mul_si(tmp20, tmp20, 11, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 1260, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_add_si(tmp16, tmp16, 1780, ctx); ca_mul_si(tmp16, tmp16, 2, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 3, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_neg(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sub_si(tmp17, tmp17, 5, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_sub_si(tmp18, tmp18, 1, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 3, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul_si(tmp16, tmp16, 5, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_add_si(tmp14, tmp14, 8, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_sub_si(tmp27, tmp27, 4, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 85, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 122, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_neg(tmp26, tmp26, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 7, ctx); ca_sub_si(tmp26, tmp26, 10, ctx); ca_mul_si(tmp26, tmp26, 11, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 630, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sub_si(tmp22, tmp22, 890, ctx); ca_mul_si(tmp22, tmp22, 2, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sub_si(tmp23, tmp23, 3, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 4896, ctx); ca_sub_si(tmp22, tmp22, 6923, ctx); ca_mul_si(tmp22, tmp22, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 79, ctx); ca_sub_si(tmp24, tmp24, 112, ctx); ca_mul_si(tmp24, tmp24, 20, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 27, ctx); ca_sub_si(tmp27, tmp27, 38, ctx); ca_mul_si(tmp27, tmp27, 7, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 342, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 484, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 2820, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 3992, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_neg(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 2, ctx); ca_sub_si(tmp31, tmp31, 3, ctx); ca_mul_si(tmp31, tmp31, 3, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, -17, ctx); ca_add_si(tmp32, tmp32, 26, ctx); ca_sqrt(tmp32, tmp32, ctx); ca_mul(tmp30, tmp31, tmp32, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 61, ctx); ca_sub(tmp29, tmp30, tmp31, ctx); ca_add_si(tmp29, tmp29, 85, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_neg(tmp30, tmp30, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, 5, ctx); ca_sub_si(tmp30, tmp30, 7, ctx); ca_mul_si(tmp30, tmp30, 11, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, -17, ctx); ca_add_si(tmp31, tmp31, 26, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sub(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 445, ctx); ca_add(tmp26, tmp27, tmp28, ctx); ca_sub_si(tmp26, tmp26, 630, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, -17, ctx); ca_add_si(tmp29, tmp29, 26, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_add(tmp27, tmp28, tmp29, ctx); ca_sub_si(tmp27, tmp27, 3, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_sub_si(tmp26, tmp26, 1, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 89, ctx); ca_sub_si(tmp26, tmp26, 126, ctx); ca_mul_si(tmp26, tmp26, 10, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 61, ctx); ca_sub_si(tmp28, tmp28, 85, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 2, ctx); ca_sub_si(tmp31, tmp31, 3, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_add_si(tmp32, tmp32, 2, ctx); ca_sqrt(tmp32, tmp32, ctx); ca_mul(tmp30, tmp31, tmp32, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 2, ctx); ca_sub(tmp29, tmp30, tmp31, ctx); ca_add_si(tmp29, tmp29, 3, ctx); ca_mul_si(tmp29, tmp29, 3, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, -17, ctx); ca_add_si(tmp30, tmp30, 26, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 61, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 85, ctx); ca_mul_si(tmp25, tmp25, 2, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_neg(tmp26, tmp26, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 5, ctx); ca_sub_si(tmp26, tmp26, 7, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 5, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_add_si(tmp24, tmp24, 7, ctx); ca_mul_si(tmp24, tmp24, 22, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 890, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_sub_si(tmp20, tmp20, 1260, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -12, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_neg(tmp24, tmp24, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul_si(tmp24, tmp24, 2, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul_si(tmp23, tmp23, 2, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 24, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 319, ctx); ca_sub_si(tmp21, tmp21, 452, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 561, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_add_si(tmp19, tmp19, 794, ctx); ca_mul_si(tmp19, tmp19, 4, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 17064, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sub_si(tmp15, tmp15, 24132, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 1, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub_si(tmp19, tmp19, 1, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_add_si(tmp16, tmp16, 1, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 1, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub_si(tmp19, tmp19, 1, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_sub_si(tmp24, tmp24, 1, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul_si(tmp22, tmp22, 5, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 8, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_sub_si(tmp25, tmp25, 1, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul_si(tmp23, tmp23, 5, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sub_si(tmp21, tmp21, 8, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 1, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub_si(tmp23, tmp23, 1, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 1, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_sub_si(tmp21, tmp21, 2, ctx); ca_pow_ui(tmp21, tmp21, 3, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_div(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sub_si(tmp15, tmp15, 1, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_set_si(tmp17, 1, ctx); ca_div_si(tmp17, tmp17, 4, ctx); ca_neg(tmp17, tmp17, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_set_si(tmp17, 1, ctx); ca_div_si(tmp17, tmp17, 2, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_set_si(tmp16, 3, ctx); ca_div_si(tmp16, tmp16, 2, ctx); ca_pow(tmp14, tmp15, tmp16, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_div(tmp10, tmp11, tmp12, ctx); ca_add(tmp8, tmp9, tmp10, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_sqrt_ui(tmp7, 2, ctx); ca_add_si(tmp7, tmp7, 2, ctx); ca_sqrt(tmp7, tmp7, ctx); ca_sub_si(tmp7, tmp7, 2, ctx); ca_div(tmp5, tmp6, tmp7, ctx); ca_add(tmp3, tmp4, tmp5, ctx); ca_mul(tmp1, tmp2, tmp3, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 3, ctx); ca_sub_si(tmp14, tmp14, 4, ctx); ca_mul_si(tmp14, tmp14, 3, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, -17, ctx); ca_add_si(tmp15, tmp15, 26, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 85, ctx); ca_sub(tmp12, tmp13, tmp14, ctx); ca_add_si(tmp12, tmp12, 122, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_neg(tmp13, tmp13, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, 7, ctx); ca_sub_si(tmp13, tmp13, 10, ctx); ca_mul_si(tmp13, tmp13, 11, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, -17, ctx); ca_add_si(tmp14, tmp14, 26, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, 630, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_sub_si(tmp9, tmp9, 890, ctx); ca_mul_si(tmp9, tmp9, 2, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, 3, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, -17, ctx); ca_add_si(tmp12, tmp12, 26, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_add(tmp10, tmp11, tmp12, ctx); ca_sub_si(tmp10, tmp10, 3, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_add_si(tmp9, tmp9, 2, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_sub_si(tmp9, tmp9, 1, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_mul_si(tmp9, tmp9, 4896, ctx); ca_sub_si(tmp9, tmp9, 6923, ctx); ca_mul_si(tmp9, tmp9, 2, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_sub(tmp6, tmp7, tmp8, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, 79, ctx); ca_sub_si(tmp11, tmp11, 112, ctx); ca_mul_si(tmp11, tmp11, 20, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_add_si(tmp12, tmp12, 2, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 27, ctx); ca_sub_si(tmp14, tmp14, 38, ctx); ca_mul_si(tmp14, tmp14, 7, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 342, ctx); ca_sub(tmp12, tmp13, tmp14, ctx); ca_add_si(tmp12, tmp12, 484, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, -17, ctx); ca_add_si(tmp13, tmp13, 26, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sub(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 2820, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_add_si(tmp8, tmp8, 3992, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_neg(tmp9, tmp9, ctx); ca_add_si(tmp9, tmp9, 2, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_add(tmp5, tmp6, tmp7, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 2, ctx); ca_sub_si(tmp18, tmp18, 3, ctx); ca_mul_si(tmp18, tmp18, 3, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 61, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_add_si(tmp16, tmp16, 85, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_neg(tmp17, tmp17, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 5, ctx); ca_sub_si(tmp17, tmp17, 7, ctx); ca_mul_si(tmp17, tmp17, 11, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, -17, ctx); ca_add_si(tmp18, tmp18, 26, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 445, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_sub_si(tmp13, tmp13, 630, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 3, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, -17, ctx); ca_add_si(tmp16, tmp16, 26, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sub_si(tmp14, tmp14, 3, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_sub_si(tmp13, tmp13, 1, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, 89, ctx); ca_sub_si(tmp13, tmp13, 126, ctx); ca_mul_si(tmp13, tmp13, 10, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 61, ctx); ca_sub_si(tmp15, tmp15, 85, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 2, ctx); ca_sub_si(tmp18, tmp18, 3, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 2, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_add_si(tmp16, tmp16, 3, ctx); ca_mul_si(tmp16, tmp16, 3, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, -17, ctx); ca_add_si(tmp17, tmp17, 26, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sub(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 61, ctx); ca_sub(tmp12, tmp13, tmp14, ctx); ca_add_si(tmp12, tmp12, 85, ctx); ca_mul_si(tmp12, tmp12, 2, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_neg(tmp13, tmp13, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, 5, ctx); ca_sub_si(tmp13, tmp13, 7, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, 5, ctx); ca_sub(tmp11, tmp12, tmp13, ctx); ca_add_si(tmp11, tmp11, 7, ctx); ca_mul_si(tmp11, tmp11, 22, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, -17, ctx); ca_add_si(tmp12, tmp12, 26, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_add(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_mul_si(tmp9, tmp9, 890, ctx); ca_add(tmp7, tmp8, tmp9, ctx); ca_sub_si(tmp7, tmp7, 1260, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, -12, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_neg(tmp11, tmp11, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul_si(tmp11, tmp11, 2, ctx); ca_sub(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, -17, ctx); ca_add_si(tmp10, tmp10, 26, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul_si(tmp10, tmp10, 2, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_add_si(tmp8, tmp8, 24, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_add(tmp4, tmp5, tmp6, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_mul_si(tmp8, tmp8, 319, ctx); ca_sub_si(tmp8, tmp8, 452, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_add_si(tmp9, tmp9, 2, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_mul_si(tmp8, tmp8, 561, ctx); ca_sub(tmp6, tmp7, tmp8, ctx); ca_add_si(tmp6, tmp6, 794, ctx); ca_mul_si(tmp6, tmp6, 4, ctx); ca_sqrt_ui(tmp7, 2, ctx); ca_mul_si(tmp7, tmp7, -17, ctx); ca_add_si(tmp7, tmp7, 26, ctx); ca_sqrt(tmp7, tmp7, ctx); ca_mul(tmp5, tmp6, tmp7, ctx); ca_add(tmp3, tmp4, tmp5, ctx); ca_sqrt_ui(tmp4, 2, ctx); ca_mul_si(tmp4, tmp4, 17064, ctx); ca_add(tmp2, tmp3, tmp4, ctx); ca_sub_si(tmp2, tmp2, 24132, ctx); ca_div(tmp0, tmp1, tmp2, ctx); ca_set_si(tmp4, 1, ctx); ca_div_si(tmp4, tmp4, 16, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, 89, ctx); ca_sub_si(tmp12, tmp12, 126, ctx); ca_mul_si(tmp12, tmp12, 5, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 61, ctx); ca_sub_si(tmp16, tmp16, 85, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sub_si(tmp19, tmp19, 3, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 4, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 6, ctx); ca_mul_si(tmp17, tmp17, 3, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, -17, ctx); ca_add_si(tmp18, tmp18, 26, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 122, ctx); ca_sub(tmp13, tmp14, tmp15, ctx); ca_add_si(tmp13, tmp13, 170, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_neg(tmp14, tmp14, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 5, ctx); ca_sub_si(tmp14, tmp14, 7, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 10, ctx); ca_sub(tmp12, tmp13, tmp14, ctx); ca_add_si(tmp12, tmp12, 14, ctx); ca_mul_si(tmp12, tmp12, 11, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, -17, ctx); ca_add_si(tmp13, tmp13, 26, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sub(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 890, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_add_si(tmp8, tmp8, 1260, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 3, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_neg(tmp11, tmp11, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_sub_si(tmp9, tmp9, 5, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, -12, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_neg(tmp11, tmp11, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul_si(tmp11, tmp11, 2, ctx); ca_sub(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, -17, ctx); ca_add_si(tmp10, tmp10, 26, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul_si(tmp10, tmp10, 2, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_add_si(tmp8, tmp8, 24, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, 63, ctx); ca_sub_si(tmp12, tmp12, 89, ctx); ca_mul_si(tmp12, tmp12, 10, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 85, ctx); ca_sub_si(tmp16, tmp16, 122, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 3, ctx); ca_sub_si(tmp19, tmp19, 4, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 6, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 8, ctx); ca_mul_si(tmp17, tmp17, 3, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, -17, ctx); ca_add_si(tmp18, tmp18, 26, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 170, ctx); ca_sub(tmp13, tmp14, tmp15, ctx); ca_add_si(tmp13, tmp13, 244, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_neg(tmp14, tmp14, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 7, ctx); ca_sub_si(tmp14, tmp14, 10, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 14, ctx); ca_sub(tmp12, tmp13, tmp14, ctx); ca_add_si(tmp12, tmp12, 20, ctx); ca_mul_si(tmp12, tmp12, 11, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, -17, ctx); ca_add_si(tmp13, tmp13, 26, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sub(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 1260, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_add_si(tmp8, tmp8, 1780, ctx); ca_mul_si(tmp8, tmp8, 2, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 3, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_neg(tmp11, tmp11, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_sub_si(tmp9, tmp9, 5, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_add(tmp5, tmp6, tmp7, ctx); ca_mul(tmp3, tmp4, tmp5, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_sub_si(tmp10, tmp10, 1, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_sub_si(tmp11, tmp11, 1, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_add_si(tmp8, tmp8, 1, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 7, ctx); ca_sub_si(tmp19, tmp19, 10, ctx); ca_mul_si(tmp19, tmp19, 44, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 7, ctx); ca_sub_si(tmp24, tmp24, 10, ctx); ca_mul_si(tmp24, tmp24, 11, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 63, ctx); ca_sub_si(tmp24, tmp24, 89, ctx); ca_mul_si(tmp24, tmp24, 10, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 3, ctx); ca_sub_si(tmp26, tmp26, 4, ctx); ca_mul_si(tmp26, tmp26, 3, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 85, ctx); ca_sub_si(tmp26, tmp26, 122, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_neg(tmp24, tmp24, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_sub_si(tmp27, tmp27, 4, ctx); ca_mul_si(tmp27, tmp27, 3, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 85, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 122, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_neg(tmp26, tmp26, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 7, ctx); ca_sub_si(tmp26, tmp26, 10, ctx); ca_mul_si(tmp26, tmp26, 11, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 630, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sub_si(tmp22, tmp22, 890, ctx); ca_mul_si(tmp22, tmp22, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub_si(tmp23, tmp23, 1, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_sub_si(tmp20, tmp20, 3, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 63, ctx); ca_sub_si(tmp18, tmp18, 89, ctx); ca_mul_si(tmp18, tmp18, 40, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 3, ctx); ca_sub_si(tmp20, tmp20, 4, ctx); ca_mul_si(tmp20, tmp20, 3, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 85, ctx); ca_sub_si(tmp20, tmp20, 122, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_mul_si(tmp17, tmp17, 4, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_neg(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 5, ctx); ca_sub_si(tmp22, tmp22, 7, ctx); ca_mul_si(tmp22, tmp22, 22, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_sub_si(tmp27, tmp27, 7, ctx); ca_mul_si(tmp27, tmp27, 11, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 89, ctx); ca_sub_si(tmp27, tmp27, 126, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 2, ctx); ca_sub_si(tmp29, tmp29, 3, ctx); ca_mul_si(tmp29, tmp29, 3, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, -17, ctx); ca_add_si(tmp29, tmp29, 26, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 61, ctx); ca_sub_si(tmp29, tmp29, 85, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_neg(tmp27, tmp27, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, 2, ctx); ca_sub_si(tmp30, tmp30, 3, ctx); ca_mul_si(tmp30, tmp30, 3, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, -17, ctx); ca_add_si(tmp31, tmp31, 26, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, 61, ctx); ca_sub(tmp28, tmp29, tmp30, ctx); ca_add_si(tmp28, tmp28, 85, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_neg(tmp29, tmp29, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 5, ctx); ca_sub_si(tmp29, tmp29, 7, ctx); ca_mul_si(tmp29, tmp29, 11, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, -17, ctx); ca_add_si(tmp30, tmp30, 26, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 445, ctx); ca_add(tmp25, tmp26, tmp27, ctx); ca_sub_si(tmp25, tmp25, 630, ctx); ca_mul_si(tmp25, tmp25, 2, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_sub_si(tmp26, tmp26, 1, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sub_si(tmp23, tmp23, 3, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 89, ctx); ca_sub_si(tmp21, tmp21, 126, ctx); ca_mul_si(tmp21, tmp21, 10, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 2, ctx); ca_sub_si(tmp23, tmp23, 3, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 61, ctx); ca_sub_si(tmp23, tmp23, 85, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_mul_si(tmp20, tmp20, 2, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_neg(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 2, ctx); ca_sub_si(tmp24, tmp24, 3, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 61, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 85, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_neg(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 5, ctx); ca_sub_si(tmp23, tmp23, 7, ctx); ca_mul_si(tmp23, tmp23, 11, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 445, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sub_si(tmp19, tmp19, 630, ctx); ca_mul_si(tmp19, tmp19, 4, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_sub_si(tmp20, tmp20, 1, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -12, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_neg(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul_si(tmp20, tmp20, 2, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 24, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 3, ctx); ca_sub_si(tmp20, tmp20, 4, ctx); ca_mul_si(tmp20, tmp20, 3, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 85, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 122, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_neg(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 7, ctx); ca_sub_si(tmp19, tmp19, 10, ctx); ca_mul_si(tmp19, tmp19, 11, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 630, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sub_si(tmp15, tmp15, 890, ctx); ca_mul_si(tmp15, tmp15, 8, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_sub_si(tmp16, tmp16, 1, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sub(tmp12, tmp13, tmp14, ctx); ca_mul_si(tmp12, tmp12, 8, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_add_si(tmp16, tmp16, 1, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_sub_si(tmp17, tmp17, 1, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_add_si(tmp14, tmp14, 1, ctx); ca_si_div(tmp14, 1, tmp14, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul_si(tmp20, tmp20, 5, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 8, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub_si(tmp23, tmp23, 1, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 3, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul_si(tmp21, tmp21, 5, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sub_si(tmp19, tmp19, 8, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 1, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_add_si(tmp19, tmp19, 1, ctx); ca_pow_ui(tmp19, tmp19, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 1, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_sub_si(tmp24, tmp24, 1, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_add(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_sub_si(tmp29, tmp29, 1, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_add(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 8, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_add_si(tmp31, tmp31, 2, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_add(tmp29, tmp30, tmp31, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_sub_si(tmp30, tmp30, 1, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 3, ctx); ca_sub(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul_si(tmp28, tmp28, 5, ctx); ca_add(tmp26, tmp27, tmp28, ctx); ca_sub_si(tmp26, tmp26, 8, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_add_si(tmp27, tmp27, 1, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_sub_si(tmp28, tmp28, 1, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_add(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 1, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_sub_si(tmp26, tmp26, 2, ctx); ca_pow_ui(tmp26, tmp26, 3, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_div(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sub_si(tmp20, tmp20, 1, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub_si(tmp19, tmp19, 2, ctx); ca_pow_ui(tmp19, tmp19, 3, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_div(tmp15, tmp16, tmp17, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sub_si(tmp24, tmp24, 4, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 85, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 122, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_neg(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 7, ctx); ca_sub_si(tmp23, tmp23, 10, ctx); ca_mul_si(tmp23, tmp23, 11, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 630, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sub_si(tmp19, tmp19, 890, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_sub_si(tmp20, tmp20, 3, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub_si(tmp19, tmp19, 1, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 4896, ctx); ca_sub_si(tmp19, tmp19, 6923, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 79, ctx); ca_sub_si(tmp21, tmp21, 112, ctx); ca_mul_si(tmp21, tmp21, 20, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 27, ctx); ca_sub_si(tmp24, tmp24, 38, ctx); ca_mul_si(tmp24, tmp24, 7, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 342, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 484, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 2820, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 3992, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_neg(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 2, ctx); ca_sub_si(tmp28, tmp28, 3, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, -17, ctx); ca_add_si(tmp29, tmp29, 26, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 61, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 85, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_neg(tmp27, tmp27, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_sub_si(tmp27, tmp27, 7, ctx); ca_mul_si(tmp27, tmp27, 11, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 445, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sub_si(tmp23, tmp23, 630, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sub_si(tmp24, tmp24, 3, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub_si(tmp23, tmp23, 1, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 89, ctx); ca_sub_si(tmp23, tmp23, 126, ctx); ca_mul_si(tmp23, tmp23, 10, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 61, ctx); ca_sub_si(tmp25, tmp25, 85, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 2, ctx); ca_sub_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 2, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 3, ctx); ca_mul_si(tmp26, tmp26, 3, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 61, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 85, ctx); ca_mul_si(tmp22, tmp22, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_neg(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 5, ctx); ca_sub_si(tmp23, tmp23, 7, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 5, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 7, ctx); ca_mul_si(tmp21, tmp21, 22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 890, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sub_si(tmp17, tmp17, 1260, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -12, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_neg(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul_si(tmp21, tmp21, 2, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul_si(tmp20, tmp20, 2, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 24, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 319, ctx); ca_sub_si(tmp18, tmp18, 452, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 561, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_add_si(tmp16, tmp16, 794, ctx); ca_mul_si(tmp16, tmp16, 4, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, -17, ctx); ca_add_si(tmp17, tmp17, 26, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 17064, ctx); ca_add(tmp12, tmp13, tmp14, ctx); ca_sub_si(tmp12, tmp12, 24132, ctx); ca_div(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 89, ctx); ca_sub_si(tmp21, tmp21, 126, ctx); ca_mul_si(tmp21, tmp21, 5, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 61, ctx); ca_sub_si(tmp25, tmp25, 85, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 2, ctx); ca_sub_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 4, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 6, ctx); ca_mul_si(tmp26, tmp26, 3, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 122, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 170, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_neg(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 5, ctx); ca_sub_si(tmp23, tmp23, 7, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 10, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 14, ctx); ca_mul_si(tmp21, tmp21, 11, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 890, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 1260, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 3, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_neg(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sub_si(tmp18, tmp18, 5, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -12, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_neg(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul_si(tmp20, tmp20, 2, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 24, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 63, ctx); ca_sub_si(tmp21, tmp21, 89, ctx); ca_mul_si(tmp21, tmp21, 10, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 85, ctx); ca_sub_si(tmp25, tmp25, 122, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sub_si(tmp28, tmp28, 4, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 6, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 8, ctx); ca_mul_si(tmp26, tmp26, 3, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 170, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 244, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_neg(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 7, ctx); ca_sub_si(tmp23, tmp23, 10, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 14, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 20, ctx); ca_mul_si(tmp21, tmp21, 11, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 1260, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 1780, ctx); ca_mul_si(tmp17, tmp17, 2, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 3, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_neg(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sub_si(tmp18, tmp18, 5, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub_si(tmp19, tmp19, 1, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 3, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul_si(tmp17, tmp17, 5, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_add_si(tmp15, tmp15, 8, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sub_si(tmp28, tmp28, 4, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, -17, ctx); ca_add_si(tmp29, tmp29, 26, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 85, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 122, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_neg(tmp27, tmp27, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 7, ctx); ca_sub_si(tmp27, tmp27, 10, ctx); ca_mul_si(tmp27, tmp27, 11, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 630, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sub_si(tmp23, tmp23, 890, ctx); ca_mul_si(tmp23, tmp23, 2, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sub_si(tmp24, tmp24, 3, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub_si(tmp23, tmp23, 1, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 4896, ctx); ca_sub_si(tmp23, tmp23, 6923, ctx); ca_mul_si(tmp23, tmp23, 2, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 79, ctx); ca_sub_si(tmp25, tmp25, 112, ctx); ca_mul_si(tmp25, tmp25, 20, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 27, ctx); ca_sub_si(tmp28, tmp28, 38, ctx); ca_mul_si(tmp28, tmp28, 7, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 342, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 484, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 2820, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 3992, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_neg(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, 2, ctx); ca_sub_si(tmp32, tmp32, 3, ctx); ca_mul_si(tmp32, tmp32, 3, ctx); ca_sqrt_ui(tmp33, 2, ctx); ca_mul_si(tmp33, tmp33, -17, ctx); ca_add_si(tmp33, tmp33, 26, ctx); ca_sqrt(tmp33, tmp33, ctx); ca_mul(tmp31, tmp32, tmp33, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, 61, ctx); ca_sub(tmp30, tmp31, tmp32, ctx); ca_add_si(tmp30, tmp30, 85, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_neg(tmp31, tmp31, ctx); ca_add_si(tmp31, tmp31, 2, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 5, ctx); ca_sub_si(tmp31, tmp31, 7, ctx); ca_mul_si(tmp31, tmp31, 11, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, -17, ctx); ca_add_si(tmp32, tmp32, 26, ctx); ca_sqrt(tmp32, tmp32, ctx); ca_mul(tmp30, tmp31, tmp32, ctx); ca_sub(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 445, ctx); ca_add(tmp27, tmp28, tmp29, ctx); ca_sub_si(tmp27, tmp27, 630, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 3, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, -17, ctx); ca_add_si(tmp30, tmp30, 26, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_add(tmp28, tmp29, tmp30, ctx); ca_sub_si(tmp28, tmp28, 3, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_sub_si(tmp27, tmp27, 1, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 89, ctx); ca_sub_si(tmp27, tmp27, 126, ctx); ca_mul_si(tmp27, tmp27, 10, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 61, ctx); ca_sub_si(tmp29, tmp29, 85, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, 2, ctx); ca_sub_si(tmp32, tmp32, 3, ctx); ca_sqrt_ui(tmp33, 2, ctx); ca_add_si(tmp33, tmp33, 2, ctx); ca_sqrt(tmp33, tmp33, ctx); ca_mul(tmp31, tmp32, tmp33, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, 2, ctx); ca_sub(tmp30, tmp31, tmp32, ctx); ca_add_si(tmp30, tmp30, 3, ctx); ca_mul_si(tmp30, tmp30, 3, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, -17, ctx); ca_add_si(tmp31, tmp31, 26, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sub(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 61, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 85, ctx); ca_mul_si(tmp26, tmp26, 2, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_neg(tmp27, tmp27, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_sub_si(tmp27, tmp27, 7, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 7, ctx); ca_mul_si(tmp25, tmp25, 22, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 890, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sub_si(tmp21, tmp21, 1260, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -12, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_neg(tmp25, tmp25, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul_si(tmp25, tmp25, 2, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul_si(tmp24, tmp24, 2, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 24, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 319, ctx); ca_sub_si(tmp22, tmp22, 452, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 561, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 794, ctx); ca_mul_si(tmp20, tmp20, 4, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 17064, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_sub_si(tmp16, tmp16, 24132, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 1, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_sub_si(tmp20, tmp20, 1, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 1, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 1, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_sub_si(tmp20, tmp20, 1, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_sub_si(tmp25, tmp25, 1, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul_si(tmp23, tmp23, 5, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 8, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_add(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_sub_si(tmp26, tmp26, 1, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul_si(tmp24, tmp24, 5, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sub_si(tmp22, tmp22, 8, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 1, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_sub_si(tmp24, tmp24, 1, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 1, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 2, ctx); ca_pow_ui(tmp22, tmp22, 3, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_div(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sub_si(tmp16, tmp16, 1, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_set_si(tmp18, 1, ctx); ca_div_si(tmp18, tmp18, 4, ctx); ca_neg(tmp18, tmp18, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_set_si(tmp18, 1, ctx); ca_div_si(tmp18, tmp18, 2, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_set_si(tmp17, 3, ctx); ca_div_si(tmp17, tmp17, 2, ctx); ca_pow(tmp15, tmp16, tmp17, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_div(tmp11, tmp12, tmp13, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_add_si(tmp8, tmp8, 2, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_add_si(tmp8, tmp8, 2, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_set_si(tmp9, 1, ctx); ca_div_si(tmp9, tmp9, 4, ctx); ca_neg(tmp9, tmp9, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_set_si(tmp9, 1, ctx); ca_div_si(tmp9, tmp9, 2, ctx); ca_add(tmp7, tmp8, tmp9, ctx); ca_sqrt(tmp7, tmp7, ctx); ca_div(tmp5, tmp6, tmp7, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_add_si(tmp12, tmp12, 2, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_sub_si(tmp13, tmp13, 1, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_add_si(tmp12, tmp12, 2, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_sub_si(tmp12, tmp12, 1, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_mul_si(tmp8, tmp8, 2, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 89, ctx); ca_sub_si(tmp19, tmp19, 126, ctx); ca_mul_si(tmp19, tmp19, 5, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 61, ctx); ca_sub_si(tmp23, tmp23, 85, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 2, ctx); ca_sub_si(tmp26, tmp26, 3, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 4, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_add_si(tmp24, tmp24, 6, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 122, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 170, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_neg(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 5, ctx); ca_sub_si(tmp21, tmp21, 7, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 10, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_add_si(tmp19, tmp19, 14, ctx); ca_mul_si(tmp19, tmp19, 11, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 890, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_add_si(tmp15, tmp15, 1260, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 3, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_neg(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_sub_si(tmp16, tmp16, 5, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, -12, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_neg(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul_si(tmp18, tmp18, 2, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, -17, ctx); ca_add_si(tmp17, tmp17, 26, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul_si(tmp17, tmp17, 2, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_add_si(tmp15, tmp15, 24, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 63, ctx); ca_sub_si(tmp19, tmp19, 89, ctx); ca_mul_si(tmp19, tmp19, 10, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 85, ctx); ca_sub_si(tmp23, tmp23, 122, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 3, ctx); ca_sub_si(tmp26, tmp26, 4, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 6, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_add_si(tmp24, tmp24, 8, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 170, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 244, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_neg(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 7, ctx); ca_sub_si(tmp21, tmp21, 10, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 14, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_add_si(tmp19, tmp19, 20, ctx); ca_mul_si(tmp19, tmp19, 11, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 1260, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_add_si(tmp15, tmp15, 1780, ctx); ca_mul_si(tmp15, tmp15, 2, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, 3, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_neg(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_sub_si(tmp16, tmp16, 5, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_add(tmp12, tmp13, tmp14, ctx); ca_mul_si(tmp12, tmp12, 8, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_add_si(tmp16, tmp16, 1, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_sub_si(tmp17, tmp17, 1, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_add_si(tmp14, tmp14, 1, ctx); ca_si_div(tmp14, 1, tmp14, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul_si(tmp20, tmp20, 5, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 8, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub_si(tmp23, tmp23, 1, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 3, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul_si(tmp21, tmp21, 5, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sub_si(tmp19, tmp19, 8, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 1, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_add_si(tmp19, tmp19, 1, ctx); ca_pow_ui(tmp19, tmp19, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 1, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_sub_si(tmp24, tmp24, 1, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_add(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_sub_si(tmp29, tmp29, 1, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_add(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 8, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_add_si(tmp31, tmp31, 2, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_add(tmp29, tmp30, tmp31, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_sub_si(tmp30, tmp30, 1, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 3, ctx); ca_sub(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul_si(tmp28, tmp28, 5, ctx); ca_add(tmp26, tmp27, tmp28, ctx); ca_sub_si(tmp26, tmp26, 8, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_add_si(tmp27, tmp27, 1, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_sub_si(tmp28, tmp28, 1, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_add(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 1, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_sub_si(tmp26, tmp26, 2, ctx); ca_pow_ui(tmp26, tmp26, 3, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_div(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sub_si(tmp20, tmp20, 1, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub_si(tmp19, tmp19, 2, ctx); ca_pow_ui(tmp19, tmp19, 3, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_div(tmp15, tmp16, tmp17, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sub_si(tmp24, tmp24, 4, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 85, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 122, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_neg(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 7, ctx); ca_sub_si(tmp23, tmp23, 10, ctx); ca_mul_si(tmp23, tmp23, 11, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 630, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sub_si(tmp19, tmp19, 890, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 3, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_add(tmp20, tmp21, tmp22, ctx); ca_sub_si(tmp20, tmp20, 3, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub_si(tmp19, tmp19, 1, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 4896, ctx); ca_sub_si(tmp19, tmp19, 6923, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 79, ctx); ca_sub_si(tmp21, tmp21, 112, ctx); ca_mul_si(tmp21, tmp21, 20, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 27, ctx); ca_sub_si(tmp24, tmp24, 38, ctx); ca_mul_si(tmp24, tmp24, 7, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 342, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 484, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 2820, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 3992, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_neg(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 2, ctx); ca_sub_si(tmp28, tmp28, 3, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, -17, ctx); ca_add_si(tmp29, tmp29, 26, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 61, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 85, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_neg(tmp27, tmp27, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_sub_si(tmp27, tmp27, 7, ctx); ca_mul_si(tmp27, tmp27, 11, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 445, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sub_si(tmp23, tmp23, 630, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sub_si(tmp24, tmp24, 3, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub_si(tmp23, tmp23, 1, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 89, ctx); ca_sub_si(tmp23, tmp23, 126, ctx); ca_mul_si(tmp23, tmp23, 10, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 61, ctx); ca_sub_si(tmp25, tmp25, 85, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 2, ctx); ca_sub_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 2, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 3, ctx); ca_mul_si(tmp26, tmp26, 3, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 61, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 85, ctx); ca_mul_si(tmp22, tmp22, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_neg(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 5, ctx); ca_sub_si(tmp23, tmp23, 7, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 5, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 7, ctx); ca_mul_si(tmp21, tmp21, 22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 890, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sub_si(tmp17, tmp17, 1260, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -12, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_neg(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul_si(tmp21, tmp21, 2, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul_si(tmp20, tmp20, 2, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_add_si(tmp18, tmp18, 24, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 319, ctx); ca_sub_si(tmp18, tmp18, 452, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 561, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_add_si(tmp16, tmp16, 794, ctx); ca_mul_si(tmp16, tmp16, 4, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, -17, ctx); ca_add_si(tmp17, tmp17, 26, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_add(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 17064, ctx); ca_add(tmp12, tmp13, tmp14, ctx); ca_sub_si(tmp12, tmp12, 24132, ctx); ca_div(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 7, ctx); ca_sub_si(tmp21, tmp21, 10, ctx); ca_mul_si(tmp21, tmp21, 44, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 7, ctx); ca_sub_si(tmp26, tmp26, 10, ctx); ca_mul_si(tmp26, tmp26, 11, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 63, ctx); ca_sub_si(tmp26, tmp26, 89, ctx); ca_mul_si(tmp26, tmp26, 10, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sub_si(tmp28, tmp28, 4, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 85, ctx); ca_sub_si(tmp28, tmp28, 122, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_neg(tmp26, tmp26, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 3, ctx); ca_sub_si(tmp29, tmp29, 4, ctx); ca_mul_si(tmp29, tmp29, 3, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, -17, ctx); ca_add_si(tmp30, tmp30, 26, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 85, ctx); ca_sub(tmp27, tmp28, tmp29, ctx); ca_add_si(tmp27, tmp27, 122, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_neg(tmp28, tmp28, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 7, ctx); ca_sub_si(tmp28, tmp28, 10, ctx); ca_mul_si(tmp28, tmp28, 11, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, -17, ctx); ca_add_si(tmp29, tmp29, 26, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 630, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sub_si(tmp24, tmp24, 890, ctx); ca_mul_si(tmp24, tmp24, 2, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_sub_si(tmp25, tmp25, 1, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_mul_si(tmp21, tmp21, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 3, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sub_si(tmp22, tmp22, 3, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, 63, ctx); ca_sub_si(tmp20, tmp20, 89, ctx); ca_mul_si(tmp20, tmp20, 40, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 3, ctx); ca_sub_si(tmp22, tmp22, 4, ctx); ca_mul_si(tmp22, tmp22, 3, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 85, ctx); ca_sub_si(tmp22, tmp22, 122, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_mul_si(tmp19, tmp19, 4, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_neg(tmp20, tmp20, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 5, ctx); ca_sub_si(tmp24, tmp24, 7, ctx); ca_mul_si(tmp24, tmp24, 22, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 5, ctx); ca_sub_si(tmp29, tmp29, 7, ctx); ca_mul_si(tmp29, tmp29, 11, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, -17, ctx); ca_add_si(tmp29, tmp29, 26, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 89, ctx); ca_sub_si(tmp29, tmp29, 126, ctx); ca_mul_si(tmp29, tmp29, 5, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 2, ctx); ca_sub_si(tmp31, tmp31, 3, ctx); ca_mul_si(tmp31, tmp31, 3, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_add_si(tmp32, tmp32, 2, ctx); ca_sqrt(tmp32, tmp32, ctx); ca_mul(tmp30, tmp31, tmp32, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, -17, ctx); ca_add_si(tmp31, tmp31, 26, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 61, ctx); ca_sub_si(tmp31, tmp31, 85, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_add_si(tmp32, tmp32, 2, ctx); ca_sqrt(tmp32, tmp32, ctx); ca_mul(tmp30, tmp31, tmp32, ctx); ca_sub(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_neg(tmp29, tmp29, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, 2, ctx); ca_sub_si(tmp32, tmp32, 3, ctx); ca_mul_si(tmp32, tmp32, 3, ctx); ca_sqrt_ui(tmp33, 2, ctx); ca_mul_si(tmp33, tmp33, -17, ctx); ca_add_si(tmp33, tmp33, 26, ctx); ca_sqrt(tmp33, tmp33, ctx); ca_mul(tmp31, tmp32, tmp33, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, 61, ctx); ca_sub(tmp30, tmp31, tmp32, ctx); ca_add_si(tmp30, tmp30, 85, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_neg(tmp31, tmp31, ctx); ca_add_si(tmp31, tmp31, 2, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 5, ctx); ca_sub_si(tmp31, tmp31, 7, ctx); ca_mul_si(tmp31, tmp31, 11, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, -17, ctx); ca_add_si(tmp32, tmp32, 26, ctx); ca_sqrt(tmp32, tmp32, ctx); ca_mul(tmp30, tmp31, tmp32, ctx); ca_sub(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 445, ctx); ca_add(tmp27, tmp28, tmp29, ctx); ca_sub_si(tmp27, tmp27, 630, ctx); ca_mul_si(tmp27, tmp27, 2, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_sub_si(tmp28, tmp28, 1, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 3, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_add(tmp25, tmp26, tmp27, ctx); ca_sub_si(tmp25, tmp25, 3, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 89, ctx); ca_sub_si(tmp23, tmp23, 126, ctx); ca_mul_si(tmp23, tmp23, 10, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 2, ctx); ca_sub_si(tmp25, tmp25, 3, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, -17, ctx); ca_add_si(tmp25, tmp25, 26, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 61, ctx); ca_sub_si(tmp25, tmp25, 85, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_mul_si(tmp22, tmp22, 2, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_neg(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 2, ctx); ca_sub_si(tmp26, tmp26, 3, ctx); ca_mul_si(tmp26, tmp26, 3, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, 61, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_add_si(tmp24, tmp24, 85, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_neg(tmp25, tmp25, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 5, ctx); ca_sub_si(tmp25, tmp25, 7, ctx); ca_mul_si(tmp25, tmp25, 11, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 445, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sub_si(tmp21, tmp21, 630, ctx); ca_mul_si(tmp21, tmp21, 4, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 1, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -12, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_neg(tmp22, tmp22, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul_si(tmp22, tmp22, 2, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul_si(tmp21, tmp21, 2, ctx); ca_sub(tmp19, tmp20, tmp21, ctx); ca_add_si(tmp19, tmp19, 24, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 3, ctx); ca_sub_si(tmp22, tmp22, 4, ctx); ca_mul_si(tmp22, tmp22, 3, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, -17, ctx); ca_add_si(tmp23, tmp23, 26, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 85, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 122, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_neg(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, 7, ctx); ca_sub_si(tmp21, tmp21, 10, ctx); ca_mul_si(tmp21, tmp21, 11, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, -17, ctx); ca_add_si(tmp22, tmp22, 26, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sub(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 630, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sub_si(tmp17, tmp17, 890, ctx); ca_mul_si(tmp17, tmp17, 8, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_sub_si(tmp18, tmp18, 1, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub_si(tmp19, tmp19, 1, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 3, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul_si(tmp17, tmp17, 5, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_add_si(tmp15, tmp15, 8, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sub_si(tmp28, tmp28, 4, ctx); ca_mul_si(tmp28, tmp28, 3, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, -17, ctx); ca_add_si(tmp29, tmp29, 26, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 85, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 122, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_neg(tmp27, tmp27, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 7, ctx); ca_sub_si(tmp27, tmp27, 10, ctx); ca_mul_si(tmp27, tmp27, 11, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, -17, ctx); ca_add_si(tmp28, tmp28, 26, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 630, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sub_si(tmp23, tmp23, 890, ctx); ca_mul_si(tmp23, tmp23, 2, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sub_si(tmp24, tmp24, 3, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_sub_si(tmp23, tmp23, 1, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 4896, ctx); ca_sub_si(tmp23, tmp23, 6923, ctx); ca_mul_si(tmp23, tmp23, 2, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 79, ctx); ca_sub_si(tmp25, tmp25, 112, ctx); ca_mul_si(tmp25, tmp25, 20, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 27, ctx); ca_sub_si(tmp28, tmp28, 38, ctx); ca_mul_si(tmp28, tmp28, 7, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_add_si(tmp29, tmp29, 2, ctx); ca_sqrt(tmp29, tmp29, ctx); ca_mul(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 342, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 484, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, -17, ctx); ca_add_si(tmp27, tmp27, 26, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 2820, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 3992, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_neg(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_add(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, 2, ctx); ca_sub_si(tmp32, tmp32, 3, ctx); ca_mul_si(tmp32, tmp32, 3, ctx); ca_sqrt_ui(tmp33, 2, ctx); ca_mul_si(tmp33, tmp33, -17, ctx); ca_add_si(tmp33, tmp33, 26, ctx); ca_sqrt(tmp33, tmp33, ctx); ca_mul(tmp31, tmp32, tmp33, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, 61, ctx); ca_sub(tmp30, tmp31, tmp32, ctx); ca_add_si(tmp30, tmp30, 85, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_neg(tmp31, tmp31, ctx); ca_add_si(tmp31, tmp31, 2, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, 5, ctx); ca_sub_si(tmp31, tmp31, 7, ctx); ca_mul_si(tmp31, tmp31, 11, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, -17, ctx); ca_add_si(tmp32, tmp32, 26, ctx); ca_sqrt(tmp32, tmp32, ctx); ca_mul(tmp30, tmp31, tmp32, ctx); ca_sub(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 445, ctx); ca_add(tmp27, tmp28, tmp29, ctx); ca_sub_si(tmp27, tmp27, 630, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 3, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_mul_si(tmp30, tmp30, -17, ctx); ca_add_si(tmp30, tmp30, 26, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_add(tmp28, tmp29, tmp30, ctx); ca_sub_si(tmp28, tmp28, 3, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_sub_si(tmp27, tmp27, 1, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 89, ctx); ca_sub_si(tmp27, tmp27, 126, ctx); ca_mul_si(tmp27, tmp27, 10, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sub(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp29, 2, ctx); ca_mul_si(tmp29, tmp29, 61, ctx); ca_sub_si(tmp29, tmp29, 85, ctx); ca_sqrt_ui(tmp30, 2, ctx); ca_add_si(tmp30, tmp30, 2, ctx); ca_sqrt(tmp30, tmp30, ctx); ca_mul(tmp28, tmp29, tmp30, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, 2, ctx); ca_sub_si(tmp32, tmp32, 3, ctx); ca_sqrt_ui(tmp33, 2, ctx); ca_add_si(tmp33, tmp33, 2, ctx); ca_sqrt(tmp33, tmp33, ctx); ca_mul(tmp31, tmp32, tmp33, ctx); ca_sqrt_ui(tmp32, 2, ctx); ca_mul_si(tmp32, tmp32, 2, ctx); ca_sub(tmp30, tmp31, tmp32, ctx); ca_add_si(tmp30, tmp30, 3, ctx); ca_mul_si(tmp30, tmp30, 3, ctx); ca_sqrt_ui(tmp31, 2, ctx); ca_mul_si(tmp31, tmp31, -17, ctx); ca_add_si(tmp31, tmp31, 26, ctx); ca_sqrt(tmp31, tmp31, ctx); ca_mul(tmp29, tmp30, tmp31, ctx); ca_sub(tmp27, tmp28, tmp29, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_mul_si(tmp28, tmp28, 61, ctx); ca_sub(tmp26, tmp27, tmp28, ctx); ca_add_si(tmp26, tmp26, 85, ctx); ca_mul_si(tmp26, tmp26, 2, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_neg(tmp27, tmp27, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_mul(tmp25, tmp26, tmp27, ctx); ca_add(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_sub_si(tmp27, tmp27, 7, ctx); ca_sqrt_ui(tmp28, 2, ctx); ca_add_si(tmp28, tmp28, 2, ctx); ca_sqrt(tmp28, tmp28, ctx); ca_mul(tmp26, tmp27, tmp28, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_mul_si(tmp27, tmp27, 5, ctx); ca_sub(tmp25, tmp26, tmp27, ctx); ca_add_si(tmp25, tmp25, 7, ctx); ca_mul_si(tmp25, tmp25, 22, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_mul_si(tmp26, tmp26, -17, ctx); ca_add_si(tmp26, tmp26, 26, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_mul_si(tmp23, tmp23, 890, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_sub_si(tmp21, tmp21, 1260, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -12, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_neg(tmp25, tmp25, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul_si(tmp25, tmp25, 2, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, -17, ctx); ca_add_si(tmp24, tmp24, 26, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul_si(tmp24, tmp24, 2, ctx); ca_sub(tmp22, tmp23, tmp24, ctx); ca_add_si(tmp22, tmp22, 24, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_add(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 319, ctx); ca_sub_si(tmp22, tmp22, 452, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul(tmp21, tmp22, tmp23, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_mul_si(tmp22, tmp22, 561, ctx); ca_sub(tmp20, tmp21, tmp22, ctx); ca_add_si(tmp20, tmp20, 794, ctx); ca_mul_si(tmp20, tmp20, 4, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_mul_si(tmp21, tmp21, -17, ctx); ca_add_si(tmp21, tmp21, 26, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 17064, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_sub_si(tmp16, tmp16, 24132, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 1, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_sub_si(tmp20, tmp20, 1, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_add(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 1, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_add_si(tmp19, tmp19, 1, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_sub_si(tmp20, tmp20, 1, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_add(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_add_si(tmp25, tmp25, 2, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_sub_si(tmp25, tmp25, 1, ctx); ca_sqrt(tmp25, tmp25, ctx); ca_mul(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_mul_si(tmp24, tmp24, 3, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_mul_si(tmp23, tmp23, 5, ctx); ca_sub(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 8, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_sqrt_ui(tmp27, 2, ctx); ca_add_si(tmp27, tmp27, 2, ctx); ca_sqrt(tmp27, tmp27, ctx); ca_add(tmp25, tmp26, tmp27, ctx); ca_sqrt_ui(tmp26, 2, ctx); ca_add_si(tmp26, tmp26, 2, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_sub_si(tmp26, tmp26, 1, ctx); ca_sqrt(tmp26, tmp26, ctx); ca_mul(tmp24, tmp25, tmp26, ctx); ca_sqrt_ui(tmp25, 2, ctx); ca_mul_si(tmp25, tmp25, 3, ctx); ca_sub(tmp23, tmp24, tmp25, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul_si(tmp24, tmp24, 5, ctx); ca_add(tmp22, tmp23, tmp24, ctx); ca_sub_si(tmp22, tmp22, 8, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_sqrt_ui(tmp21, 2, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_sqrt(tmp21, tmp21, ctx); ca_add_si(tmp21, tmp21, 2, ctx); ca_mul(tmp19, tmp20, tmp21, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_add_si(tmp23, tmp23, 1, ctx); ca_sqrt_ui(tmp24, 2, ctx); ca_add_si(tmp24, tmp24, 2, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_sub_si(tmp24, tmp24, 1, ctx); ca_sqrt(tmp24, tmp24, ctx); ca_mul(tmp22, tmp23, tmp24, ctx); ca_sqrt_ui(tmp23, 2, ctx); ca_add_si(tmp23, tmp23, 2, ctx); ca_sqrt(tmp23, tmp23, ctx); ca_add(tmp21, tmp22, tmp23, ctx); ca_add_si(tmp21, tmp21, 1, ctx); ca_sqrt_ui(tmp22, 2, ctx); ca_add_si(tmp22, tmp22, 2, ctx); ca_sqrt(tmp22, tmp22, ctx); ca_sub_si(tmp22, tmp22, 2, ctx); ca_pow_ui(tmp22, tmp22, 3, ctx); ca_mul(tmp20, tmp21, tmp22, ctx); ca_div(tmp18, tmp19, tmp20, ctx); ca_sub(tmp16, tmp17, tmp18, ctx); ca_sub_si(tmp16, tmp16, 1, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_set_si(tmp18, 1, ctx); ca_div_si(tmp18, tmp18, 4, ctx); ca_neg(tmp18, tmp18, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_add_si(tmp19, tmp19, 2, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_set_si(tmp18, 1, ctx); ca_div_si(tmp18, tmp18, 2, ctx); ca_add(tmp16, tmp17, tmp18, ctx); ca_set_si(tmp17, 3, ctx); ca_div_si(tmp17, tmp17, 2, ctx); ca_pow(tmp15, tmp16, tmp17, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_div(tmp11, tmp12, tmp13, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_add_si(tmp8, tmp8, 2, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_sub_si(tmp8, tmp8, 2, ctx); ca_div(tmp6, tmp7, tmp8, ctx); ca_sub(tmp4, tmp5, tmp6, ctx); ca_mul(tmp2, tmp3, tmp4, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 3, ctx); ca_sub_si(tmp15, tmp15, 4, ctx); ca_mul_si(tmp15, tmp15, 3, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, -17, ctx); ca_add_si(tmp16, tmp16, 26, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 85, ctx); ca_sub(tmp13, tmp14, tmp15, ctx); ca_add_si(tmp13, tmp13, 122, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_neg(tmp14, tmp14, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 7, ctx); ca_sub_si(tmp14, tmp14, 10, ctx); ca_mul_si(tmp14, tmp14, 11, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, -17, ctx); ca_add_si(tmp15, tmp15, 26, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sub(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, 630, ctx); ca_add(tmp10, tmp11, tmp12, ctx); ca_sub_si(tmp10, tmp10, 890, ctx); ca_mul_si(tmp10, tmp10, 2, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, 3, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, -17, ctx); ca_add_si(tmp13, tmp13, 26, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_add(tmp11, tmp12, tmp13, ctx); ca_sub_si(tmp11, tmp11, 3, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_sub_si(tmp10, tmp10, 1, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 4896, ctx); ca_sub_si(tmp10, tmp10, 6923, ctx); ca_mul_si(tmp10, tmp10, 2, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_sub(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, 79, ctx); ca_sub_si(tmp12, tmp12, 112, ctx); ca_mul_si(tmp12, tmp12, 20, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_add_si(tmp13, tmp13, 2, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 27, ctx); ca_sub_si(tmp15, tmp15, 38, ctx); ca_mul_si(tmp15, tmp15, 7, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 342, ctx); ca_sub(tmp13, tmp14, tmp15, ctx); ca_add_si(tmp13, tmp13, 484, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, -17, ctx); ca_add_si(tmp14, tmp14, 26, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, 2820, ctx); ca_sub(tmp9, tmp10, tmp11, ctx); ca_add_si(tmp9, tmp9, 3992, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_neg(tmp10, tmp10, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_add(tmp6, tmp7, tmp8, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sub_si(tmp19, tmp19, 3, ctx); ca_mul_si(tmp19, tmp19, 3, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_mul_si(tmp20, tmp20, -17, ctx); ca_add_si(tmp20, tmp20, 26, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 61, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 85, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_neg(tmp18, tmp18, ctx); ca_add_si(tmp18, tmp18, 2, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, 5, ctx); ca_sub_si(tmp18, tmp18, 7, ctx); ca_mul_si(tmp18, tmp18, 11, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, -17, ctx); ca_add_si(tmp19, tmp19, 26, ctx); ca_sqrt(tmp19, tmp19, ctx); ca_mul(tmp17, tmp18, tmp19, ctx); ca_sub(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 445, ctx); ca_add(tmp14, tmp15, tmp16, ctx); ca_sub_si(tmp14, tmp14, 630, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 3, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_mul_si(tmp17, tmp17, -17, ctx); ca_add_si(tmp17, tmp17, 26, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_add(tmp15, tmp16, tmp17, ctx); ca_sub_si(tmp15, tmp15, 3, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_sub_si(tmp14, tmp14, 1, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 89, ctx); ca_sub_si(tmp14, tmp14, 126, ctx); ca_mul_si(tmp14, tmp14, 10, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sub(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul_si(tmp16, tmp16, 61, ctx); ca_sub_si(tmp16, tmp16, 85, ctx); ca_sqrt_ui(tmp17, 2, ctx); ca_add_si(tmp17, tmp17, 2, ctx); ca_sqrt(tmp17, tmp17, ctx); ca_mul(tmp15, tmp16, tmp17, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sub_si(tmp19, tmp19, 3, ctx); ca_sqrt_ui(tmp20, 2, ctx); ca_add_si(tmp20, tmp20, 2, ctx); ca_sqrt(tmp20, tmp20, ctx); ca_mul(tmp18, tmp19, tmp20, ctx); ca_sqrt_ui(tmp19, 2, ctx); ca_mul_si(tmp19, tmp19, 2, ctx); ca_sub(tmp17, tmp18, tmp19, ctx); ca_add_si(tmp17, tmp17, 3, ctx); ca_mul_si(tmp17, tmp17, 3, ctx); ca_sqrt_ui(tmp18, 2, ctx); ca_mul_si(tmp18, tmp18, -17, ctx); ca_add_si(tmp18, tmp18, 26, ctx); ca_sqrt(tmp18, tmp18, ctx); ca_mul(tmp16, tmp17, tmp18, ctx); ca_sub(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, 61, ctx); ca_sub(tmp13, tmp14, tmp15, ctx); ca_add_si(tmp13, tmp13, 85, ctx); ca_mul_si(tmp13, tmp13, 2, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_neg(tmp14, tmp14, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_add(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 5, ctx); ca_sub_si(tmp14, tmp14, 7, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_add_si(tmp15, tmp15, 2, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul_si(tmp14, tmp14, 5, ctx); ca_sub(tmp12, tmp13, tmp14, ctx); ca_add_si(tmp12, tmp12, 7, ctx); ca_mul_si(tmp12, tmp12, 22, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, -17, ctx); ca_add_si(tmp13, tmp13, 26, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 890, ctx); ca_add(tmp8, tmp9, tmp10, ctx); ca_sub_si(tmp8, tmp8, 1260, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, -12, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_neg(tmp12, tmp12, ctx); ca_add_si(tmp12, tmp12, 2, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul_si(tmp12, tmp12, 2, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, -17, ctx); ca_add_si(tmp11, tmp11, 26, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul_si(tmp11, tmp11, 2, ctx); ca_sub(tmp9, tmp10, tmp11, ctx); ca_add_si(tmp9, tmp9, 24, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_add(tmp5, tmp6, tmp7, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_mul_si(tmp9, tmp9, 319, ctx); ca_sub_si(tmp9, tmp9, 452, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_mul_si(tmp9, tmp9, 561, ctx); ca_sub(tmp7, tmp8, tmp9, ctx); ca_add_si(tmp7, tmp7, 794, ctx); ca_mul_si(tmp7, tmp7, 4, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_mul_si(tmp8, tmp8, -17, ctx); ca_add_si(tmp8, tmp8, 26, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_add(tmp4, tmp5, tmp6, ctx); ca_sqrt_ui(tmp5, 2, ctx); ca_mul_si(tmp5, tmp5, 17064, ctx); ca_add(tmp3, tmp4, tmp5, ctx); ca_sub_si(tmp3, tmp3, 24132, ctx); ca_div(tmp1, tmp2, tmp3, ctx); ca_sub(N, tmp0, tmp1, ctx); TIMEIT_ONCE_STOP flint_printf("Evaluating M...\n"); TIMEIT_ONCE_START ca_sqrt_ui(tmp6, 2, ctx); ca_mul_si(tmp6, tmp6, 6, ctx); ca_sqrt_ui(tmp7, 2, ctx); ca_neg(tmp7, tmp7, ctx); ca_add_si(tmp7, tmp7, 2, ctx); ca_sqrt(tmp7, tmp7, ctx); ca_add(tmp5, tmp6, tmp7, ctx); ca_sqrt_ui(tmp6, 2, ctx); ca_mul_si(tmp6, tmp6, -17, ctx); ca_add_si(tmp6, tmp6, 26, ctx); ca_sqrt(tmp6, tmp6, ctx); ca_add(tmp4, tmp5, tmp6, ctx); ca_sub_si(tmp4, tmp4, 8, ctx); ca_mul_si(tmp4, tmp4, 4, ctx); ca_sqrt_ui(tmp6, 2, ctx); ca_mul_si(tmp6, tmp6, 3, ctx); ca_sqrt_ui(tmp7, 2, ctx); ca_neg(tmp7, tmp7, ctx); ca_add_si(tmp7, tmp7, 2, ctx); ca_sqrt(tmp7, tmp7, ctx); ca_add(tmp5, tmp6, tmp7, ctx); ca_sub_si(tmp5, tmp5, 5, ctx); ca_sqrt(tmp5, tmp5, ctx); ca_mul(tmp3, tmp4, tmp5, ctx); ca_sqrt_ui(tmp6, 2, ctx); ca_mul_si(tmp6, tmp6, 3, ctx); ca_sqrt_ui(tmp7, 2, ctx); ca_mul_si(tmp7, tmp7, -17, ctx); ca_add_si(tmp7, tmp7, 26, ctx); ca_sqrt(tmp7, tmp7, ctx); ca_add(tmp5, tmp6, tmp7, ctx); ca_sub_si(tmp5, tmp5, 3, ctx); ca_sqrt(tmp5, tmp5, ctx); ca_i(tmp10, ctx); ca_mul_si(tmp10, tmp10, -24, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_i(tmp11, ctx); ca_mul_si(tmp11, tmp11, 4, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_neg(tmp12, tmp12, ctx); ca_add_si(tmp12, tmp12, 2, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_i(tmp10, ctx); ca_mul_si(tmp10, tmp10, 4, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, -17, ctx); ca_add_si(tmp11, tmp11, 26, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_sub(tmp7, tmp8, tmp9, ctx); ca_i(tmp8, ctx); ca_mul_si(tmp8, tmp8, 32, ctx); ca_add(tmp6, tmp7, tmp8, ctx); ca_mul(tmp4, tmp5, tmp6, ctx); ca_sub(tmp2, tmp3, tmp4, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_neg(tmp10, tmp10, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, -17, ctx); ca_add_si(tmp11, tmp11, 26, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_add(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_mul_si(tmp8, tmp8, 8, ctx); ca_sub(tmp6, tmp7, tmp8, ctx); ca_add_si(tmp6, tmp6, 12, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_mul_si(tmp8, tmp8, 3, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_neg(tmp9, tmp9, ctx); ca_add_si(tmp9, tmp9, 2, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_add(tmp7, tmp8, tmp9, ctx); ca_sub_si(tmp7, tmp7, 5, ctx); ca_sqrt(tmp7, tmp7, ctx); ca_mul(tmp5, tmp6, tmp7, ctx); ca_i(tmp12, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_neg(tmp12, tmp12, ctx); ca_add_si(tmp12, tmp12, 2, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_i(tmp13, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, -17, ctx); ca_add_si(tmp13, tmp13, 26, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_mul(tmp11, tmp12, tmp13, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_i(tmp11, ctx); ca_mul_si(tmp11, tmp11, 8, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_i(tmp9, ctx); ca_mul_si(tmp9, tmp9, 12, ctx); ca_add(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_mul_si(tmp9, tmp9, 3, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, -17, ctx); ca_add_si(tmp10, tmp10, 26, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_add(tmp8, tmp9, tmp10, ctx); ca_sub_si(tmp8, tmp8, 3, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_add(tmp4, tmp5, tmp6, ctx); ca_sqrt_ui(tmp7, 2, ctx); ca_mul_si(tmp7, tmp7, -12, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_neg(tmp8, tmp8, ctx); ca_add_si(tmp8, tmp8, 2, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_mul_si(tmp8, tmp8, 2, ctx); ca_sub(tmp6, tmp7, tmp8, ctx); ca_sqrt_ui(tmp7, 2, ctx); ca_mul_si(tmp7, tmp7, -17, ctx); ca_add_si(tmp7, tmp7, 26, ctx); ca_sqrt(tmp7, tmp7, ctx); ca_mul_si(tmp7, tmp7, 2, ctx); ca_sub(tmp5, tmp6, tmp7, ctx); ca_add_si(tmp5, tmp5, 24, ctx); ca_sqrt(tmp5, tmp5, ctx); ca_mul(tmp3, tmp4, tmp5, ctx); ca_sub(tmp1, tmp2, tmp3, ctx); ca_i(tmp10, ctx); ca_mul_si(tmp10, tmp10, 24, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_i(tmp11, ctx); ca_mul_si(tmp11, tmp11, 4, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, -17, ctx); ca_add_si(tmp12, tmp12, 26, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_mul(tmp10, tmp11, tmp12, ctx); ca_add(tmp8, tmp9, tmp10, ctx); ca_i(tmp9, ctx); ca_mul_si(tmp9, tmp9, 32, ctx); ca_sub(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_neg(tmp8, tmp8, ctx); ca_add_si(tmp8, tmp8, 2, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_i(tmp9, ctx); ca_mul_si(tmp9, tmp9, 8, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 3, ctx); ca_sub_si(tmp10, tmp10, 4, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_mul_si(tmp9, tmp9, -17, ctx); ca_add_si(tmp9, tmp9, 26, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_add(tmp5, tmp6, tmp7, ctx); ca_i(tmp7, ctx); ca_mul_si(tmp7, tmp7, 228, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_sub(tmp4, tmp5, tmp6, ctx); ca_i(tmp5, ctx); ca_mul_si(tmp5, tmp5, 328, ctx); ca_add(tmp3, tmp4, tmp5, ctx); ca_sqrt_ui(tmp4, 2, ctx); ca_add_si(tmp4, tmp4, 2, ctx); ca_sqrt(tmp4, tmp4, ctx); ca_sub_si(tmp4, tmp4, 1, ctx); ca_sqrt(tmp4, tmp4, ctx); ca_mul(tmp2, tmp3, tmp4, ctx); ca_sub(tmp0, tmp1, tmp2, ctx); ca_neg(tmp0, tmp0, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 6, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_neg(tmp11, tmp11, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, -17, ctx); ca_add_si(tmp10, tmp10, 26, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_add(tmp8, tmp9, tmp10, ctx); ca_sub_si(tmp8, tmp8, 8, ctx); ca_mul_si(tmp8, tmp8, 4, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 3, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, -17, ctx); ca_add_si(tmp11, tmp11, 26, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_sub_si(tmp9, tmp9, 3, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_add_si(tmp8, tmp8, 2, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_sub_si(tmp8, tmp8, 1, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_mul_si(tmp10, tmp10, 3, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_neg(tmp11, tmp11, ctx); ca_add_si(tmp11, tmp11, 2, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_sub_si(tmp9, tmp9, 5, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_i(tmp14, ctx); ca_mul_si(tmp14, tmp14, -24, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_i(tmp15, ctx); ca_mul_si(tmp15, tmp15, 4, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_neg(tmp16, tmp16, ctx); ca_add_si(tmp16, tmp16, 2, ctx); ca_sqrt(tmp16, tmp16, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sub(tmp12, tmp13, tmp14, ctx); ca_i(tmp14, ctx); ca_mul_si(tmp14, tmp14, 4, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, -17, ctx); ca_add_si(tmp15, tmp15, 26, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sub(tmp11, tmp12, tmp13, ctx); ca_i(tmp12, ctx); ca_mul_si(tmp12, tmp12, 32, ctx); ca_add(tmp10, tmp11, tmp12, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_add_si(tmp9, tmp9, 2, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_sub_si(tmp9, tmp9, 1, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_add(tmp5, tmp6, tmp7, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_mul_si(tmp8, tmp8, 6, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_mul_si(tmp9, tmp9, -17, ctx); ca_add_si(tmp9, tmp9, 26, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_add(tmp7, tmp8, tmp9, ctx); ca_sub_si(tmp7, tmp7, 8, ctx); ca_mul_si(tmp7, tmp7, 4, ctx); ca_sqrt_ui(tmp8, 2, ctx); ca_neg(tmp8, tmp8, ctx); ca_add_si(tmp8, tmp8, 2, ctx); ca_sqrt(tmp8, tmp8, ctx); ca_mul(tmp6, tmp7, tmp8, ctx); ca_sub(tmp4, tmp5, tmp6, ctx); ca_i(tmp14, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_neg(tmp14, tmp14, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_i(tmp15, ctx); ca_sqrt_ui(tmp16, 2, ctx); ca_mul(tmp14, tmp15, tmp16, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, -17, ctx); ca_add_si(tmp15, tmp15, 26, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_add(tmp11, tmp12, tmp13, ctx); ca_i(tmp13, ctx); ca_mul_si(tmp13, tmp13, 8, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_i(tmp11, ctx); ca_mul_si(tmp11, tmp11, 12, ctx); ca_add(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp11, 2, ctx); ca_mul_si(tmp11, tmp11, 3, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_neg(tmp12, tmp12, ctx); ca_add_si(tmp12, tmp12, 2, ctx); ca_sqrt(tmp12, tmp12, ctx); ca_add(tmp10, tmp11, tmp12, ctx); ca_sub_si(tmp10, tmp10, 5, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_add_si(tmp9, tmp9, 2, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_sub_si(tmp9, tmp9, 1, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul(tmp7, tmp8, tmp9, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_neg(tmp14, tmp14, ctx); ca_add_si(tmp14, tmp14, 2, ctx); ca_sqrt(tmp14, tmp14, ctx); ca_mul(tmp12, tmp13, tmp14, ctx); ca_sqrt_ui(tmp14, 2, ctx); ca_sqrt_ui(tmp15, 2, ctx); ca_mul_si(tmp15, tmp15, -17, ctx); ca_add_si(tmp15, tmp15, 26, ctx); ca_sqrt(tmp15, tmp15, ctx); ca_mul(tmp13, tmp14, tmp15, ctx); ca_add(tmp11, tmp12, tmp13, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, 8, ctx); ca_sub(tmp10, tmp11, tmp12, ctx); ca_add_si(tmp10, tmp10, 12, ctx); ca_sqrt_ui(tmp12, 2, ctx); ca_mul_si(tmp12, tmp12, 3, ctx); ca_sqrt_ui(tmp13, 2, ctx); ca_mul_si(tmp13, tmp13, -17, ctx); ca_add_si(tmp13, tmp13, 26, ctx); ca_sqrt(tmp13, tmp13, ctx); ca_add(tmp11, tmp12, tmp13, ctx); ca_sub_si(tmp11, tmp11, 3, ctx); ca_sqrt(tmp11, tmp11, ctx); ca_mul(tmp9, tmp10, tmp11, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_sub_si(tmp10, tmp10, 1, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul(tmp8, tmp9, tmp10, ctx); ca_sub(tmp6, tmp7, tmp8, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_mul_si(tmp9, tmp9, -12, ctx); ca_sqrt_ui(tmp10, 2, ctx); ca_neg(tmp10, tmp10, ctx); ca_add_si(tmp10, tmp10, 2, ctx); ca_sqrt(tmp10, tmp10, ctx); ca_mul_si(tmp10, tmp10, 2, ctx); ca_sub(tmp8, tmp9, tmp10, ctx); ca_sqrt_ui(tmp9, 2, ctx); ca_mul_si(tmp9, tmp9, -17, ctx); ca_add_si(tmp9, tmp9, 26, ctx); ca_sqrt(tmp9, tmp9, ctx); ca_mul_si(tmp9, tmp9, 2, ctx); ca_sub(tmp7, tmp8, tmp9, ctx); ca_add_si(tmp7, tmp7, 24, ctx); ca_sqrt(tmp7, tmp7, ctx); ca_mul(tmp5, tmp6, tmp7, ctx); ca_add(tmp3, tmp4, tmp5, ctx); ca_sqrt_ui(tmp5, 2, ctx); ca_mul_si(tmp5, tmp5, 3, ctx); ca_sub_si(tmp5, tmp5, 4, ctx); ca_mul_si(tmp5, tmp5, 8, ctx); ca_sqrt_ui(tmp6, 2, ctx); ca_mul_si(tmp6, tmp6, -17, ctx); ca_add_si(tmp6, tmp6, 26, ctx); ca_sqrt(tmp6, tmp6, ctx); ca_mul(tmp4, tmp5, tmp6, ctx); ca_sub(tmp2, tmp3, tmp4, ctx); ca_sqrt_ui(tmp3, 2, ctx); ca_mul_si(tmp3, tmp3, 228, ctx); ca_add(tmp1, tmp2, tmp3, ctx); ca_sub_si(tmp1, tmp1, 328, ctx); ca_div(M, tmp0, tmp1, ctx); TIMEIT_ONCE_STOP flint_printf("Evaluating E = -(1-|M|^2)^2...\n"); TIMEIT_ONCE_START ca_abs(E, M, ctx); ca_pow_ui(E, E, 2, ctx); ca_si_sub(E, 1, E, ctx); ca_pow_ui(E, E, 2, ctx); ca_neg(E, E, ctx); TIMEIT_ONCE_STOP flint_printf("N ~ "); ca_printn(N, 50, ctx); flint_printf("\n"); flint_printf("E ~ "); ca_printn(E, 50, ctx); flint_printf("\n"); ctx->options[CA_OPT_QQBAR_DEG_LIMIT] = 10000; flint_printf("Testing E = N...\n"); TIMEIT_ONCE_START equal = ca_check_equal(E, N, ctx); TIMEIT_ONCE_STOP flint_printf("\nEqual = "); truth_print(equal); flint_printf("\n"); ca_clear(tmp0, ctx); ca_clear(tmp1, ctx); ca_clear(tmp2, ctx); ca_clear(tmp3, ctx); ca_clear(tmp4, ctx); ca_clear(tmp5, ctx); ca_clear(tmp6, ctx); ca_clear(tmp7, ctx); ca_clear(tmp8, ctx); ca_clear(tmp9, ctx); ca_clear(tmp10, ctx); ca_clear(tmp11, ctx); ca_clear(tmp12, ctx); ca_clear(tmp13, ctx); ca_clear(tmp14, ctx); ca_clear(tmp15, ctx); ca_clear(tmp16, ctx); ca_clear(tmp17, ctx); ca_clear(tmp18, ctx); ca_clear(tmp19, ctx); ca_clear(tmp20, ctx); ca_clear(tmp21, ctx); ca_clear(tmp22, ctx); ca_clear(tmp23, ctx); ca_clear(tmp24, ctx); ca_clear(tmp25, ctx); ca_clear(tmp26, ctx); ca_clear(tmp27, ctx); ca_clear(tmp28, ctx); ca_clear(tmp29, ctx); ca_clear(tmp30, ctx); ca_clear(tmp31, ctx); ca_clear(tmp32, ctx); ca_clear(tmp33, ctx); ca_clear(tmp34, ctx); ca_clear(N, ctx); ca_clear(M, ctx); ca_clear(E, ctx); ca_ctx_clear(ctx); } void main_qqbar() { qqbar_t N, M, E; qqbar_t tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, tmp11, tmp12, tmp13, tmp14, tmp15, tmp16, tmp17, tmp18, tmp19, tmp20, tmp21, tmp22, tmp23, tmp24, tmp25, tmp26, tmp27, tmp28, tmp29, tmp30, tmp31, tmp32, tmp33, tmp34; truth_t equal; qqbar_init(N); qqbar_init(M); qqbar_init(E); qqbar_init(tmp0); qqbar_init(tmp1); qqbar_init(tmp2); qqbar_init(tmp3); qqbar_init(tmp4); qqbar_init(tmp5); qqbar_init(tmp6); qqbar_init(tmp7); qqbar_init(tmp8); qqbar_init(tmp9); qqbar_init(tmp10); qqbar_init(tmp11); qqbar_init(tmp12); qqbar_init(tmp13); qqbar_init(tmp14); qqbar_init(tmp15); qqbar_init(tmp16); qqbar_init(tmp17); qqbar_init(tmp18); qqbar_init(tmp19); qqbar_init(tmp20); qqbar_init(tmp21); qqbar_init(tmp22); qqbar_init(tmp23); qqbar_init(tmp24); qqbar_init(tmp25); qqbar_init(tmp26); qqbar_init(tmp27); qqbar_init(tmp28); qqbar_init(tmp29); qqbar_init(tmp30); qqbar_init(tmp31); qqbar_init(tmp32); qqbar_init(tmp33); qqbar_init(tmp34); flint_printf("Evaluating N...\n"); TIMEIT_ONCE_START qqbar_set_si(tmp3, 1); qqbar_div_si(tmp3, tmp3, 16); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, 7); qqbar_sub_si(tmp11, tmp11, 10); qqbar_mul_si(tmp11, tmp11, 44); qqbar_sqrt_ui(tmp12, 2); qqbar_add_si(tmp12, tmp12, 2); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, -17); qqbar_add_si(tmp11, tmp11, 26); qqbar_sqrt(tmp11, tmp11); qqbar_mul(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 7); qqbar_sub_si(tmp16, tmp16, 10); qqbar_mul_si(tmp16, tmp16, 11); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, -17); qqbar_add_si(tmp16, tmp16, 26); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 63); qqbar_sub_si(tmp16, tmp16, 89); qqbar_mul_si(tmp16, tmp16, 10); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sub(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 3); qqbar_sub_si(tmp18, tmp18, 4); qqbar_mul_si(tmp18, tmp18, 3); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, -17); qqbar_add_si(tmp18, tmp18, 26); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 85); qqbar_sub_si(tmp18, tmp18, 122); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_neg(tmp16, tmp16); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sub(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 3); qqbar_sub_si(tmp19, tmp19, 4); qqbar_mul_si(tmp19, tmp19, 3); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 85); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 122); qqbar_sqrt_ui(tmp18, 2); qqbar_neg(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 7); qqbar_sub_si(tmp18, tmp18, 10); qqbar_mul_si(tmp18, tmp18, 11); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 630); qqbar_add(tmp14, tmp15, tmp16); qqbar_sub_si(tmp14, tmp14, 890); qqbar_mul_si(tmp14, tmp14, 2); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_sub_si(tmp15, tmp15, 1); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_add(tmp11, tmp12, tmp13); qqbar_mul_si(tmp11, tmp11, 2); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, 3); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, -17); qqbar_add_si(tmp14, tmp14, 26); qqbar_sqrt(tmp14, tmp14); qqbar_add(tmp12, tmp13, tmp14); qqbar_sub_si(tmp12, tmp12, 3); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_add(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 63); qqbar_sub_si(tmp10, tmp10, 89); qqbar_mul_si(tmp10, tmp10, 40); qqbar_sqrt_ui(tmp11, 2); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_mul(tmp9, tmp10, tmp11); qqbar_sub(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, 3); qqbar_sub_si(tmp12, tmp12, 4); qqbar_mul_si(tmp12, tmp12, 3); qqbar_sqrt_ui(tmp13, 2); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, -17); qqbar_add_si(tmp12, tmp12, 26); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, 85); qqbar_sub_si(tmp12, tmp12, 122); qqbar_sqrt_ui(tmp13, 2); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sub(tmp9, tmp10, tmp11); qqbar_mul_si(tmp9, tmp9, 4); qqbar_sqrt_ui(tmp10, 2); qqbar_neg(tmp10, tmp10); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_mul(tmp8, tmp9, tmp10); qqbar_sub(tmp6, tmp7, tmp8); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 5); qqbar_sub_si(tmp14, tmp14, 7); qqbar_mul_si(tmp14, tmp14, 22); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, -17); qqbar_add_si(tmp14, tmp14, 26); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 5); qqbar_sub_si(tmp19, tmp19, 7); qqbar_mul_si(tmp19, tmp19, 11); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 89); qqbar_sub_si(tmp19, tmp19, 126); qqbar_mul_si(tmp19, tmp19, 5); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 2); qqbar_sub_si(tmp21, tmp21, 3); qqbar_mul_si(tmp21, tmp21, 3); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 61); qqbar_sub_si(tmp21, tmp21, 85); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_neg(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 2); qqbar_sub_si(tmp22, tmp22, 3); qqbar_mul_si(tmp22, tmp22, 3); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 61); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 85); qqbar_sqrt_ui(tmp21, 2); qqbar_neg(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 5); qqbar_sub_si(tmp21, tmp21, 7); qqbar_mul_si(tmp21, tmp21, 11); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 445); qqbar_add(tmp17, tmp18, tmp19); qqbar_sub_si(tmp17, tmp17, 630); qqbar_mul_si(tmp17, tmp17, 2); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_sub_si(tmp18, tmp18, 1); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_add(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 3); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, -17); qqbar_add_si(tmp17, tmp17, 26); qqbar_sqrt(tmp17, tmp17); qqbar_add(tmp15, tmp16, tmp17); qqbar_sub_si(tmp15, tmp15, 3); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_add(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, 89); qqbar_sub_si(tmp13, tmp13, 126); qqbar_mul_si(tmp13, tmp13, 10); qqbar_sqrt_ui(tmp14, 2); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sub(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 2); qqbar_sub_si(tmp15, tmp15, 3); qqbar_mul_si(tmp15, tmp15, 3); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, -17); qqbar_add_si(tmp15, tmp15, 26); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 61); qqbar_sub_si(tmp15, tmp15, 85); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sub(tmp12, tmp13, tmp14); qqbar_mul_si(tmp12, tmp12, 2); qqbar_sqrt_ui(tmp13, 2); qqbar_neg(tmp13, tmp13); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sub(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 2); qqbar_sub_si(tmp16, tmp16, 3); qqbar_mul_si(tmp16, tmp16, 3); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, -17); qqbar_add_si(tmp17, tmp17, 26); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 61); qqbar_sub(tmp14, tmp15, tmp16); qqbar_add_si(tmp14, tmp14, 85); qqbar_sqrt_ui(tmp15, 2); qqbar_neg(tmp15, tmp15); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 5); qqbar_sub_si(tmp15, tmp15, 7); qqbar_mul_si(tmp15, tmp15, 11); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, -17); qqbar_add_si(tmp16, tmp16, 26); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sub(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, 445); qqbar_add(tmp11, tmp12, tmp13); qqbar_sub_si(tmp11, tmp11, 630); qqbar_mul_si(tmp11, tmp11, 4); qqbar_sqrt_ui(tmp12, 2); qqbar_add_si(tmp12, tmp12, 2); qqbar_sqrt(tmp12, tmp12); qqbar_sub_si(tmp12, tmp12, 1); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_add(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, -12); qqbar_sqrt_ui(tmp12, 2); qqbar_neg(tmp12, tmp12); qqbar_add_si(tmp12, tmp12, 2); qqbar_sqrt(tmp12, tmp12); qqbar_mul_si(tmp12, tmp12, 2); qqbar_sub(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, -17); qqbar_add_si(tmp11, tmp11, 26); qqbar_sqrt(tmp11, tmp11); qqbar_mul_si(tmp11, tmp11, 2); qqbar_sub(tmp9, tmp10, tmp11); qqbar_add_si(tmp9, tmp9, 24); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_add(tmp5, tmp6, tmp7); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, 3); qqbar_sub_si(tmp12, tmp12, 4); qqbar_mul_si(tmp12, tmp12, 3); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, -17); qqbar_add_si(tmp13, tmp13, 26); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, 85); qqbar_sub(tmp10, tmp11, tmp12); qqbar_add_si(tmp10, tmp10, 122); qqbar_sqrt_ui(tmp11, 2); qqbar_neg(tmp11, tmp11); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_mul(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, 7); qqbar_sub_si(tmp11, tmp11, 10); qqbar_mul_si(tmp11, tmp11, 11); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, -17); qqbar_add_si(tmp12, tmp12, 26); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_sub(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp9, 2); qqbar_mul_si(tmp9, tmp9, 630); qqbar_add(tmp7, tmp8, tmp9); qqbar_sub_si(tmp7, tmp7, 890); qqbar_mul_si(tmp7, tmp7, 8); qqbar_sqrt_ui(tmp8, 2); qqbar_add_si(tmp8, tmp8, 2); qqbar_sqrt(tmp8, tmp8); qqbar_sub_si(tmp8, tmp8, 1); qqbar_sqrt(tmp8, tmp8); qqbar_mul(tmp6, tmp7, tmp8); qqbar_add(tmp4, tmp5, tmp6); qqbar_mul(tmp2, tmp3, tmp4); qqbar_sqrt_ui(tmp11, 2); qqbar_sqrt_ui(tmp12, 2); qqbar_add_si(tmp12, tmp12, 2); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp11, 2); qqbar_sub(tmp9, tmp10, tmp11); qqbar_sub_si(tmp9, tmp9, 1); qqbar_sqrt_ui(tmp10, 2); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_sub_si(tmp10, tmp10, 1); qqbar_sqrt(tmp10, tmp10); qqbar_mul(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp9, 2); qqbar_add_si(tmp9, tmp9, 2); qqbar_sqrt(tmp9, tmp9); qqbar_add(tmp7, tmp8, tmp9); qqbar_sub_si(tmp7, tmp7, 1); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 89); qqbar_sub_si(tmp18, tmp18, 126); qqbar_mul_si(tmp18, tmp18, 5); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 61); qqbar_sub_si(tmp22, tmp22, 85); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 2); qqbar_sub_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 4); qqbar_sub(tmp23, tmp24, tmp25); qqbar_add_si(tmp23, tmp23, 6); qqbar_mul_si(tmp23, tmp23, 3); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 122); qqbar_sub(tmp19, tmp20, tmp21); qqbar_add_si(tmp19, tmp19, 170); qqbar_sqrt_ui(tmp20, 2); qqbar_neg(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 5); qqbar_sub_si(tmp20, tmp20, 7); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 10); qqbar_sub(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 14); qqbar_mul_si(tmp18, tmp18, 11); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 890); qqbar_sub(tmp14, tmp15, tmp16); qqbar_add_si(tmp14, tmp14, 1260); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 3); qqbar_sqrt_ui(tmp17, 2); qqbar_neg(tmp17, tmp17); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_add(tmp15, tmp16, tmp17); qqbar_sub_si(tmp15, tmp15, 5); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, -12); qqbar_sqrt_ui(tmp17, 2); qqbar_neg(tmp17, tmp17); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_mul_si(tmp17, tmp17, 2); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, -17); qqbar_add_si(tmp16, tmp16, 26); qqbar_sqrt(tmp16, tmp16); qqbar_mul_si(tmp16, tmp16, 2); qqbar_sub(tmp14, tmp15, tmp16); qqbar_add_si(tmp14, tmp14, 24); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 63); qqbar_sub_si(tmp18, tmp18, 89); qqbar_mul_si(tmp18, tmp18, 10); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 85); qqbar_sub_si(tmp22, tmp22, 122); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sub_si(tmp25, tmp25, 4); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 6); qqbar_sub(tmp23, tmp24, tmp25); qqbar_add_si(tmp23, tmp23, 8); qqbar_mul_si(tmp23, tmp23, 3); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 170); qqbar_sub(tmp19, tmp20, tmp21); qqbar_add_si(tmp19, tmp19, 244); qqbar_sqrt_ui(tmp20, 2); qqbar_neg(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 7); qqbar_sub_si(tmp20, tmp20, 10); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 14); qqbar_sub(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 20); qqbar_mul_si(tmp18, tmp18, 11); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 1260); qqbar_sub(tmp14, tmp15, tmp16); qqbar_add_si(tmp14, tmp14, 1780); qqbar_mul_si(tmp14, tmp14, 2); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 3); qqbar_sqrt_ui(tmp17, 2); qqbar_neg(tmp17, tmp17); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_add(tmp15, tmp16, tmp17); qqbar_sub_si(tmp15, tmp15, 5); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_add(tmp11, tmp12, tmp13); qqbar_mul_si(tmp11, tmp11, 8); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_add_si(tmp15, tmp15, 1); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_sub_si(tmp16, tmp16, 1); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_add(tmp13, tmp14, tmp15); qqbar_add_si(tmp13, tmp13, 1); qqbar_si_div(tmp13, 1, tmp13); qqbar_sqrt_ui(tmp21, 2); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_add(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_sub_si(tmp21, tmp21, 1); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 3); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul_si(tmp19, tmp19, 5); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 8); qqbar_sqrt_ui(tmp22, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_add(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 3); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul_si(tmp20, tmp20, 5); qqbar_add(tmp18, tmp19, tmp20); qqbar_sub_si(tmp18, tmp18, 8); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_add_si(tmp17, tmp17, 2); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 1); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_sub_si(tmp21, tmp21, 1); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_add(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 1); qqbar_pow_ui(tmp18, tmp18, 2); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 1); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub_si(tmp23, tmp23, 1); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp28, 2); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_add(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_sub_si(tmp28, tmp28, 1); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 3); qqbar_add(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul_si(tmp26, tmp26, 5); qqbar_sub(tmp24, tmp25, tmp26); qqbar_add_si(tmp24, tmp24, 8); qqbar_sqrt_ui(tmp29, 2); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_add(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_sub_si(tmp29, tmp29, 1); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sub(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul_si(tmp27, tmp27, 5); qqbar_add(tmp25, tmp26, tmp27); qqbar_sub_si(tmp25, tmp25, 8); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_add_si(tmp24, tmp24, 2); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_add_si(tmp26, tmp26, 1); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_sub_si(tmp27, tmp27, 1); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_add(tmp24, tmp25, tmp26); qqbar_add_si(tmp24, tmp24, 1); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_sub_si(tmp25, tmp25, 2); qqbar_pow_ui(tmp25, tmp25, 3); qqbar_mul(tmp23, tmp24, tmp25); qqbar_div(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sub_si(tmp19, tmp19, 1); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_sub_si(tmp18, tmp18, 2); qqbar_pow_ui(tmp18, tmp18, 3); qqbar_mul(tmp16, tmp17, tmp18); qqbar_div(tmp14, tmp15, tmp16); qqbar_add(tmp12, tmp13, tmp14); qqbar_mul(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 3); qqbar_sub_si(tmp23, tmp23, 4); qqbar_mul_si(tmp23, tmp23, 3); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 85); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 122); qqbar_sqrt_ui(tmp22, 2); qqbar_neg(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 7); qqbar_sub_si(tmp22, tmp22, 10); qqbar_mul_si(tmp22, tmp22, 11); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 630); qqbar_add(tmp18, tmp19, tmp20); qqbar_sub_si(tmp18, tmp18, 890); qqbar_mul_si(tmp18, tmp18, 2); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 3); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_add(tmp19, tmp20, tmp21); qqbar_sub_si(tmp19, tmp19, 3); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_sub_si(tmp18, tmp18, 1); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 4896); qqbar_sub_si(tmp18, tmp18, 6923); qqbar_mul_si(tmp18, tmp18, 2); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 79); qqbar_sub_si(tmp20, tmp20, 112); qqbar_mul_si(tmp20, tmp20, 20); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 27); qqbar_sub_si(tmp23, tmp23, 38); qqbar_mul_si(tmp23, tmp23, 7); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 342); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 484); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 2820); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 3992); qqbar_sqrt_ui(tmp18, 2); qqbar_neg(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_add(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 2); qqbar_sub_si(tmp27, tmp27, 3); qqbar_mul_si(tmp27, tmp27, 3); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 61); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 85); qqbar_sqrt_ui(tmp26, 2); qqbar_neg(tmp26, tmp26); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 5); qqbar_sub_si(tmp26, tmp26, 7); qqbar_mul_si(tmp26, tmp26, 11); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 445); qqbar_add(tmp22, tmp23, tmp24); qqbar_sub_si(tmp22, tmp22, 630); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_add(tmp23, tmp24, tmp25); qqbar_sub_si(tmp23, tmp23, 3); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 89); qqbar_sub_si(tmp22, tmp22, 126); qqbar_mul_si(tmp22, tmp22, 10); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 61); qqbar_sub_si(tmp24, tmp24, 85); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 2); qqbar_sub_si(tmp27, tmp27, 3); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 2); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 3); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 61); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 85); qqbar_mul_si(tmp21, tmp21, 2); qqbar_sqrt_ui(tmp22, 2); qqbar_neg(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 5); qqbar_sub_si(tmp22, tmp22, 7); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 5); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 7); qqbar_mul_si(tmp20, tmp20, 22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_add(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 890); qqbar_add(tmp16, tmp17, tmp18); qqbar_sub_si(tmp16, tmp16, 1260); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -12); qqbar_sqrt_ui(tmp20, 2); qqbar_neg(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul_si(tmp20, tmp20, 2); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 24); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_add(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 319); qqbar_sub_si(tmp17, tmp17, 452); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 561); qqbar_sub(tmp15, tmp16, tmp17); qqbar_add_si(tmp15, tmp15, 794); qqbar_mul_si(tmp15, tmp15, 4); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, -17); qqbar_add_si(tmp16, tmp16, 26); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_add(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, 17064); qqbar_add(tmp11, tmp12, tmp13); qqbar_sub_si(tmp11, tmp11, 24132); qqbar_div(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 7); qqbar_sub_si(tmp20, tmp20, 10); qqbar_mul_si(tmp20, tmp20, 44); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 7); qqbar_sub_si(tmp25, tmp25, 10); qqbar_mul_si(tmp25, tmp25, 11); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 63); qqbar_sub_si(tmp25, tmp25, 89); qqbar_mul_si(tmp25, tmp25, 10); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 3); qqbar_sub_si(tmp27, tmp27, 4); qqbar_mul_si(tmp27, tmp27, 3); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 85); qqbar_sub_si(tmp27, tmp27, 122); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sub(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_neg(tmp25, tmp25); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sub(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sub_si(tmp28, tmp28, 4); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, -17); qqbar_add_si(tmp29, tmp29, 26); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 85); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 122); qqbar_sqrt_ui(tmp27, 2); qqbar_neg(tmp27, tmp27); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 7); qqbar_sub_si(tmp27, tmp27, 10); qqbar_mul_si(tmp27, tmp27, 11); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sub(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 630); qqbar_add(tmp23, tmp24, tmp25); qqbar_sub_si(tmp23, tmp23, 890); qqbar_mul_si(tmp23, tmp23, 2); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_sub_si(tmp24, tmp24, 1); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_add(tmp20, tmp21, tmp22); qqbar_mul_si(tmp20, tmp20, 2); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 3); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_add(tmp21, tmp22, tmp23); qqbar_sub_si(tmp21, tmp21, 3); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_add(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 63); qqbar_sub_si(tmp19, tmp19, 89); qqbar_mul_si(tmp19, tmp19, 40); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 3); qqbar_sub_si(tmp21, tmp21, 4); qqbar_mul_si(tmp21, tmp21, 3); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 85); qqbar_sub_si(tmp21, tmp21, 122); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_mul_si(tmp18, tmp18, 4); qqbar_sqrt_ui(tmp19, 2); qqbar_neg(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 5); qqbar_sub_si(tmp23, tmp23, 7); qqbar_mul_si(tmp23, tmp23, 22); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 5); qqbar_sub_si(tmp28, tmp28, 7); qqbar_mul_si(tmp28, tmp28, 11); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 89); qqbar_sub_si(tmp28, tmp28, 126); qqbar_mul_si(tmp28, tmp28, 5); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sub(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, 2); qqbar_sub_si(tmp30, tmp30, 3); qqbar_mul_si(tmp30, tmp30, 3); qqbar_sqrt_ui(tmp31, 2); qqbar_add_si(tmp31, tmp31, 2); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, -17); qqbar_add_si(tmp30, tmp30, 26); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, 61); qqbar_sub_si(tmp30, tmp30, 85); qqbar_sqrt_ui(tmp31, 2); qqbar_add_si(tmp31, tmp31, 2); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sub(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_neg(tmp28, tmp28); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sub(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 2); qqbar_sub_si(tmp31, tmp31, 3); qqbar_mul_si(tmp31, tmp31, 3); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, -17); qqbar_add_si(tmp32, tmp32, 26); qqbar_sqrt(tmp32, tmp32); qqbar_mul(tmp30, tmp31, tmp32); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 61); qqbar_sub(tmp29, tmp30, tmp31); qqbar_add_si(tmp29, tmp29, 85); qqbar_sqrt_ui(tmp30, 2); qqbar_neg(tmp30, tmp30); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, 5); qqbar_sub_si(tmp30, tmp30, 7); qqbar_mul_si(tmp30, tmp30, 11); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, -17); qqbar_add_si(tmp31, tmp31, 26); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sub(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 445); qqbar_add(tmp26, tmp27, tmp28); qqbar_sub_si(tmp26, tmp26, 630); qqbar_mul_si(tmp26, tmp26, 2); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_sub_si(tmp27, tmp27, 1); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_add(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_add(tmp24, tmp25, tmp26); qqbar_sub_si(tmp24, tmp24, 3); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_add(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 89); qqbar_sub_si(tmp22, tmp22, 126); qqbar_mul_si(tmp22, tmp22, 10); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 2); qqbar_sub_si(tmp24, tmp24, 3); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 61); qqbar_sub_si(tmp24, tmp24, 85); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sub(tmp21, tmp22, tmp23); qqbar_mul_si(tmp21, tmp21, 2); qqbar_sqrt_ui(tmp22, 2); qqbar_neg(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 2); qqbar_sub_si(tmp25, tmp25, 3); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 61); qqbar_sub(tmp23, tmp24, tmp25); qqbar_add_si(tmp23, tmp23, 85); qqbar_sqrt_ui(tmp24, 2); qqbar_neg(tmp24, tmp24); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 5); qqbar_sub_si(tmp24, tmp24, 7); qqbar_mul_si(tmp24, tmp24, 11); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sub(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 445); qqbar_add(tmp20, tmp21, tmp22); qqbar_sub_si(tmp20, tmp20, 630); qqbar_mul_si(tmp20, tmp20, 4); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_sub_si(tmp21, tmp21, 1); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_add(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -12); qqbar_sqrt_ui(tmp21, 2); qqbar_neg(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul_si(tmp21, tmp21, 2); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul_si(tmp20, tmp20, 2); qqbar_sub(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 24); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_add(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 3); qqbar_sub_si(tmp21, tmp21, 4); qqbar_mul_si(tmp21, tmp21, 3); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 85); qqbar_sub(tmp19, tmp20, tmp21); qqbar_add_si(tmp19, tmp19, 122); qqbar_sqrt_ui(tmp20, 2); qqbar_neg(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 7); qqbar_sub_si(tmp20, tmp20, 10); qqbar_mul_si(tmp20, tmp20, 11); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 630); qqbar_add(tmp16, tmp17, tmp18); qqbar_sub_si(tmp16, tmp16, 890); qqbar_mul_si(tmp16, tmp16, 8); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_sub_si(tmp17, tmp17, 1); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_add(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp18, 2); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_add(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_sub_si(tmp18, tmp18, 1); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 3); qqbar_add(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_mul_si(tmp16, tmp16, 5); qqbar_sub(tmp14, tmp15, tmp16); qqbar_add_si(tmp14, tmp14, 8); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp13, 2); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 3); qqbar_sub_si(tmp27, tmp27, 4); qqbar_mul_si(tmp27, tmp27, 3); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 85); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 122); qqbar_sqrt_ui(tmp26, 2); qqbar_neg(tmp26, tmp26); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 7); qqbar_sub_si(tmp26, tmp26, 10); qqbar_mul_si(tmp26, tmp26, 11); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 630); qqbar_add(tmp22, tmp23, tmp24); qqbar_sub_si(tmp22, tmp22, 890); qqbar_mul_si(tmp22, tmp22, 2); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_add(tmp23, tmp24, tmp25); qqbar_sub_si(tmp23, tmp23, 3); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 4896); qqbar_sub_si(tmp22, tmp22, 6923); qqbar_mul_si(tmp22, tmp22, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 79); qqbar_sub_si(tmp24, tmp24, 112); qqbar_mul_si(tmp24, tmp24, 20); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 27); qqbar_sub_si(tmp27, tmp27, 38); qqbar_mul_si(tmp27, tmp27, 7); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 342); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 484); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 2820); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 3992); qqbar_sqrt_ui(tmp22, 2); qqbar_neg(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 2); qqbar_sub_si(tmp31, tmp31, 3); qqbar_mul_si(tmp31, tmp31, 3); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, -17); qqbar_add_si(tmp32, tmp32, 26); qqbar_sqrt(tmp32, tmp32); qqbar_mul(tmp30, tmp31, tmp32); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 61); qqbar_sub(tmp29, tmp30, tmp31); qqbar_add_si(tmp29, tmp29, 85); qqbar_sqrt_ui(tmp30, 2); qqbar_neg(tmp30, tmp30); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, 5); qqbar_sub_si(tmp30, tmp30, 7); qqbar_mul_si(tmp30, tmp30, 11); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, -17); qqbar_add_si(tmp31, tmp31, 26); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sub(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 445); qqbar_add(tmp26, tmp27, tmp28); qqbar_sub_si(tmp26, tmp26, 630); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, -17); qqbar_add_si(tmp29, tmp29, 26); qqbar_sqrt(tmp29, tmp29); qqbar_add(tmp27, tmp28, tmp29); qqbar_sub_si(tmp27, tmp27, 3); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_sub_si(tmp26, tmp26, 1); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 89); qqbar_sub_si(tmp26, tmp26, 126); qqbar_mul_si(tmp26, tmp26, 10); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 61); qqbar_sub_si(tmp28, tmp28, 85); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 2); qqbar_sub_si(tmp31, tmp31, 3); qqbar_sqrt_ui(tmp32, 2); qqbar_add_si(tmp32, tmp32, 2); qqbar_sqrt(tmp32, tmp32); qqbar_mul(tmp30, tmp31, tmp32); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 2); qqbar_sub(tmp29, tmp30, tmp31); qqbar_add_si(tmp29, tmp29, 3); qqbar_mul_si(tmp29, tmp29, 3); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, -17); qqbar_add_si(tmp30, tmp30, 26); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sub(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 61); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 85); qqbar_mul_si(tmp25, tmp25, 2); qqbar_sqrt_ui(tmp26, 2); qqbar_neg(tmp26, tmp26); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_add(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 5); qqbar_sub_si(tmp26, tmp26, 7); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 5); qqbar_sub(tmp24, tmp25, tmp26); qqbar_add_si(tmp24, tmp24, 7); qqbar_mul_si(tmp24, tmp24, 22); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_add(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 890); qqbar_add(tmp20, tmp21, tmp22); qqbar_sub_si(tmp20, tmp20, 1260); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -12); qqbar_sqrt_ui(tmp24, 2); qqbar_neg(tmp24, tmp24); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul_si(tmp24, tmp24, 2); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul_si(tmp23, tmp23, 2); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 24); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_add(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 319); qqbar_sub_si(tmp21, tmp21, 452); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 561); qqbar_sub(tmp19, tmp20, tmp21); qqbar_add_si(tmp19, tmp19, 794); qqbar_mul_si(tmp19, tmp19, 4); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_add(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 17064); qqbar_add(tmp15, tmp16, tmp17); qqbar_sub_si(tmp15, tmp15, 24132); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 1); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub_si(tmp19, tmp19, 1); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_add(tmp16, tmp17, tmp18); qqbar_add_si(tmp16, tmp16, 1); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 1); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub_si(tmp19, tmp19, 1); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp24, 2); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_add(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_sub_si(tmp24, tmp24, 1); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 3); qqbar_add(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul_si(tmp22, tmp22, 5); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 8); qqbar_sqrt_ui(tmp25, 2); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_add(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_sub_si(tmp25, tmp25, 1); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul_si(tmp23, tmp23, 5); qqbar_add(tmp21, tmp22, tmp23); qqbar_sub_si(tmp21, tmp21, 8); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 1); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub_si(tmp23, tmp23, 1); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_add(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 1); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_sub_si(tmp21, tmp21, 2); qqbar_pow_ui(tmp21, tmp21, 3); qqbar_mul(tmp19, tmp20, tmp21); qqbar_div(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sub_si(tmp15, tmp15, 1); qqbar_mul(tmp13, tmp14, tmp15); qqbar_set_si(tmp17, 1); qqbar_div_si(tmp17, tmp17, 4); qqbar_neg(tmp17, tmp17); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_set_si(tmp17, 1); qqbar_div_si(tmp17, tmp17, 2); qqbar_add(tmp15, tmp16, tmp17); qqbar_set_si(tmp16, 3); qqbar_div_si(tmp16, tmp16, 2); qqbar_pow(tmp14, tmp15, tmp16); qqbar_mul(tmp12, tmp13, tmp14); qqbar_div(tmp10, tmp11, tmp12); qqbar_add(tmp8, tmp9, tmp10); qqbar_mul(tmp6, tmp7, tmp8); qqbar_sqrt_ui(tmp7, 2); qqbar_add_si(tmp7, tmp7, 2); qqbar_sqrt(tmp7, tmp7); qqbar_add_si(tmp7, tmp7, 2); qqbar_sqrt(tmp7, tmp7); qqbar_mul(tmp5, tmp6, tmp7); qqbar_set_si(tmp8, 1); qqbar_div_si(tmp8, tmp8, 4); qqbar_neg(tmp8, tmp8); qqbar_sqrt_ui(tmp9, 2); qqbar_add_si(tmp9, tmp9, 2); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_set_si(tmp8, 1); qqbar_div_si(tmp8, tmp8, 2); qqbar_add(tmp6, tmp7, tmp8); qqbar_sqrt(tmp6, tmp6); qqbar_div(tmp4, tmp5, tmp6); qqbar_sqrt_ui(tmp11, 2); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_sqrt_ui(tmp12, 2); qqbar_sub_si(tmp12, tmp12, 1); qqbar_mul(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp11, 2); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_sub_si(tmp11, tmp11, 1); qqbar_sqrt(tmp11, tmp11); qqbar_mul(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_sub(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp9, 2); qqbar_add_si(tmp9, tmp9, 2); qqbar_sqrt(tmp9, tmp9); qqbar_add(tmp7, tmp8, tmp9); qqbar_mul_si(tmp7, tmp7, 2); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 7); qqbar_sub_si(tmp18, tmp18, 10); qqbar_mul_si(tmp18, tmp18, 44); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, -17); qqbar_add_si(tmp18, tmp18, 26); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 7); qqbar_sub_si(tmp23, tmp23, 10); qqbar_mul_si(tmp23, tmp23, 11); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 63); qqbar_sub_si(tmp23, tmp23, 89); qqbar_mul_si(tmp23, tmp23, 10); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sub_si(tmp25, tmp25, 4); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 85); qqbar_sub_si(tmp25, tmp25, 122); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_neg(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 3); qqbar_sub_si(tmp26, tmp26, 4); qqbar_mul_si(tmp26, tmp26, 3); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 85); qqbar_sub(tmp24, tmp25, tmp26); qqbar_add_si(tmp24, tmp24, 122); qqbar_sqrt_ui(tmp25, 2); qqbar_neg(tmp25, tmp25); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 7); qqbar_sub_si(tmp25, tmp25, 10); qqbar_mul_si(tmp25, tmp25, 11); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 630); qqbar_add(tmp21, tmp22, tmp23); qqbar_sub_si(tmp21, tmp21, 890); qqbar_mul_si(tmp21, tmp21, 2); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_mul_si(tmp18, tmp18, 2); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 3); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_add(tmp19, tmp20, tmp21); qqbar_sub_si(tmp19, tmp19, 3); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 63); qqbar_sub_si(tmp17, tmp17, 89); qqbar_mul_si(tmp17, tmp17, 40); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sub(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 3); qqbar_sub_si(tmp19, tmp19, 4); qqbar_mul_si(tmp19, tmp19, 3); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 85); qqbar_sub_si(tmp19, tmp19, 122); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_mul_si(tmp16, tmp16, 4); qqbar_sqrt_ui(tmp17, 2); qqbar_neg(tmp17, tmp17); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sub(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 5); qqbar_sub_si(tmp21, tmp21, 7); qqbar_mul_si(tmp21, tmp21, 22); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 5); qqbar_sub_si(tmp26, tmp26, 7); qqbar_mul_si(tmp26, tmp26, 11); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 89); qqbar_sub_si(tmp26, tmp26, 126); qqbar_mul_si(tmp26, tmp26, 5); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 2); qqbar_sub_si(tmp28, tmp28, 3); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 61); qqbar_sub_si(tmp28, tmp28, 85); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sub(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_neg(tmp26, tmp26); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 2); qqbar_sub_si(tmp29, tmp29, 3); qqbar_mul_si(tmp29, tmp29, 3); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, -17); qqbar_add_si(tmp30, tmp30, 26); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 61); qqbar_sub(tmp27, tmp28, tmp29); qqbar_add_si(tmp27, tmp27, 85); qqbar_sqrt_ui(tmp28, 2); qqbar_neg(tmp28, tmp28); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 5); qqbar_sub_si(tmp28, tmp28, 7); qqbar_mul_si(tmp28, tmp28, 11); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, -17); qqbar_add_si(tmp29, tmp29, 26); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sub(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 445); qqbar_add(tmp24, tmp25, tmp26); qqbar_sub_si(tmp24, tmp24, 630); qqbar_mul_si(tmp24, tmp24, 2); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_sub_si(tmp25, tmp25, 1); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sub(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 3); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_add(tmp22, tmp23, tmp24); qqbar_sub_si(tmp22, tmp22, 3); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 89); qqbar_sub_si(tmp20, tmp20, 126); qqbar_mul_si(tmp20, tmp20, 10); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 2); qqbar_sub_si(tmp22, tmp22, 3); qqbar_mul_si(tmp22, tmp22, 3); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 61); qqbar_sub_si(tmp22, tmp22, 85); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sqrt_ui(tmp20, 2); qqbar_neg(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 2); qqbar_sub_si(tmp23, tmp23, 3); qqbar_mul_si(tmp23, tmp23, 3); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 61); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 85); qqbar_sqrt_ui(tmp22, 2); qqbar_neg(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 5); qqbar_sub_si(tmp22, tmp22, 7); qqbar_mul_si(tmp22, tmp22, 11); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 445); qqbar_add(tmp18, tmp19, tmp20); qqbar_sub_si(tmp18, tmp18, 630); qqbar_mul_si(tmp18, tmp18, 4); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub_si(tmp19, tmp19, 1); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, -12); qqbar_sqrt_ui(tmp19, 2); qqbar_neg(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, -17); qqbar_add_si(tmp18, tmp18, 26); qqbar_sqrt(tmp18, tmp18); qqbar_mul_si(tmp18, tmp18, 2); qqbar_sub(tmp16, tmp17, tmp18); qqbar_add_si(tmp16, tmp16, 24); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_add(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 3); qqbar_sub_si(tmp19, tmp19, 4); qqbar_mul_si(tmp19, tmp19, 3); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 85); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 122); qqbar_sqrt_ui(tmp18, 2); qqbar_neg(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 7); qqbar_sub_si(tmp18, tmp18, 10); qqbar_mul_si(tmp18, tmp18, 11); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 630); qqbar_add(tmp14, tmp15, tmp16); qqbar_sub_si(tmp14, tmp14, 890); qqbar_mul_si(tmp14, tmp14, 8); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_sub_si(tmp15, tmp15, 1); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sub(tmp11, tmp12, tmp13); qqbar_mul_si(tmp11, tmp11, 8); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_add_si(tmp15, tmp15, 1); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_sub_si(tmp16, tmp16, 1); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_add(tmp13, tmp14, tmp15); qqbar_add_si(tmp13, tmp13, 1); qqbar_si_div(tmp13, 1, tmp13); qqbar_sqrt_ui(tmp21, 2); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_add(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_sub_si(tmp21, tmp21, 1); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 3); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul_si(tmp19, tmp19, 5); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 8); qqbar_sqrt_ui(tmp22, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_add(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 3); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul_si(tmp20, tmp20, 5); qqbar_add(tmp18, tmp19, tmp20); qqbar_sub_si(tmp18, tmp18, 8); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_add_si(tmp17, tmp17, 2); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 1); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_sub_si(tmp21, tmp21, 1); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_add(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 1); qqbar_pow_ui(tmp18, tmp18, 2); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 1); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub_si(tmp23, tmp23, 1); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp28, 2); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_add(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_sub_si(tmp28, tmp28, 1); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 3); qqbar_add(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul_si(tmp26, tmp26, 5); qqbar_sub(tmp24, tmp25, tmp26); qqbar_add_si(tmp24, tmp24, 8); qqbar_sqrt_ui(tmp29, 2); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_add(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_sub_si(tmp29, tmp29, 1); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sub(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul_si(tmp27, tmp27, 5); qqbar_add(tmp25, tmp26, tmp27); qqbar_sub_si(tmp25, tmp25, 8); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_add_si(tmp24, tmp24, 2); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_add_si(tmp26, tmp26, 1); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_sub_si(tmp27, tmp27, 1); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_add(tmp24, tmp25, tmp26); qqbar_add_si(tmp24, tmp24, 1); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_sub_si(tmp25, tmp25, 2); qqbar_pow_ui(tmp25, tmp25, 3); qqbar_mul(tmp23, tmp24, tmp25); qqbar_div(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sub_si(tmp19, tmp19, 1); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_sub_si(tmp18, tmp18, 2); qqbar_pow_ui(tmp18, tmp18, 3); qqbar_mul(tmp16, tmp17, tmp18); qqbar_div(tmp14, tmp15, tmp16); qqbar_add(tmp12, tmp13, tmp14); qqbar_mul(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 3); qqbar_sub_si(tmp23, tmp23, 4); qqbar_mul_si(tmp23, tmp23, 3); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 85); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 122); qqbar_sqrt_ui(tmp22, 2); qqbar_neg(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 7); qqbar_sub_si(tmp22, tmp22, 10); qqbar_mul_si(tmp22, tmp22, 11); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 630); qqbar_add(tmp18, tmp19, tmp20); qqbar_sub_si(tmp18, tmp18, 890); qqbar_mul_si(tmp18, tmp18, 2); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 3); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_add(tmp19, tmp20, tmp21); qqbar_sub_si(tmp19, tmp19, 3); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_sub_si(tmp18, tmp18, 1); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 4896); qqbar_sub_si(tmp18, tmp18, 6923); qqbar_mul_si(tmp18, tmp18, 2); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 79); qqbar_sub_si(tmp20, tmp20, 112); qqbar_mul_si(tmp20, tmp20, 20); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 27); qqbar_sub_si(tmp23, tmp23, 38); qqbar_mul_si(tmp23, tmp23, 7); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 342); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 484); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 2820); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 3992); qqbar_sqrt_ui(tmp18, 2); qqbar_neg(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_add(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 2); qqbar_sub_si(tmp27, tmp27, 3); qqbar_mul_si(tmp27, tmp27, 3); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 61); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 85); qqbar_sqrt_ui(tmp26, 2); qqbar_neg(tmp26, tmp26); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 5); qqbar_sub_si(tmp26, tmp26, 7); qqbar_mul_si(tmp26, tmp26, 11); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 445); qqbar_add(tmp22, tmp23, tmp24); qqbar_sub_si(tmp22, tmp22, 630); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_add(tmp23, tmp24, tmp25); qqbar_sub_si(tmp23, tmp23, 3); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 89); qqbar_sub_si(tmp22, tmp22, 126); qqbar_mul_si(tmp22, tmp22, 10); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 61); qqbar_sub_si(tmp24, tmp24, 85); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 2); qqbar_sub_si(tmp27, tmp27, 3); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 2); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 3); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 61); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 85); qqbar_mul_si(tmp21, tmp21, 2); qqbar_sqrt_ui(tmp22, 2); qqbar_neg(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 5); qqbar_sub_si(tmp22, tmp22, 7); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 5); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 7); qqbar_mul_si(tmp20, tmp20, 22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_add(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 890); qqbar_add(tmp16, tmp17, tmp18); qqbar_sub_si(tmp16, tmp16, 1260); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -12); qqbar_sqrt_ui(tmp20, 2); qqbar_neg(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul_si(tmp20, tmp20, 2); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 24); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_add(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 319); qqbar_sub_si(tmp17, tmp17, 452); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 561); qqbar_sub(tmp15, tmp16, tmp17); qqbar_add_si(tmp15, tmp15, 794); qqbar_mul_si(tmp15, tmp15, 4); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, -17); qqbar_add_si(tmp16, tmp16, 26); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_add(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, 17064); qqbar_add(tmp11, tmp12, tmp13); qqbar_sub_si(tmp11, tmp11, 24132); qqbar_div(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 89); qqbar_sub_si(tmp20, tmp20, 126); qqbar_mul_si(tmp20, tmp20, 5); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 61); qqbar_sub_si(tmp24, tmp24, 85); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 2); qqbar_sub_si(tmp27, tmp27, 3); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 4); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 6); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 122); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 170); qqbar_sqrt_ui(tmp22, 2); qqbar_neg(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 5); qqbar_sub_si(tmp22, tmp22, 7); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 10); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 14); qqbar_mul_si(tmp20, tmp20, 11); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 890); qqbar_sub(tmp16, tmp17, tmp18); qqbar_add_si(tmp16, tmp16, 1260); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 3); qqbar_sqrt_ui(tmp19, 2); qqbar_neg(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_add(tmp17, tmp18, tmp19); qqbar_sub_si(tmp17, tmp17, 5); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, -12); qqbar_sqrt_ui(tmp19, 2); qqbar_neg(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, -17); qqbar_add_si(tmp18, tmp18, 26); qqbar_sqrt(tmp18, tmp18); qqbar_mul_si(tmp18, tmp18, 2); qqbar_sub(tmp16, tmp17, tmp18); qqbar_add_si(tmp16, tmp16, 24); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 63); qqbar_sub_si(tmp20, tmp20, 89); qqbar_mul_si(tmp20, tmp20, 10); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 85); qqbar_sub_si(tmp24, tmp24, 122); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 3); qqbar_sub_si(tmp27, tmp27, 4); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 6); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 8); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 170); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 244); qqbar_sqrt_ui(tmp22, 2); qqbar_neg(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 7); qqbar_sub_si(tmp22, tmp22, 10); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 14); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 20); qqbar_mul_si(tmp20, tmp20, 11); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 1260); qqbar_sub(tmp16, tmp17, tmp18); qqbar_add_si(tmp16, tmp16, 1780); qqbar_mul_si(tmp16, tmp16, 2); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 3); qqbar_sqrt_ui(tmp19, 2); qqbar_neg(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_add(tmp17, tmp18, tmp19); qqbar_sub_si(tmp17, tmp17, 5); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_add(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp18, 2); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_add(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_sub_si(tmp18, tmp18, 1); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 3); qqbar_add(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_mul_si(tmp16, tmp16, 5); qqbar_sub(tmp14, tmp15, tmp16); qqbar_add_si(tmp14, tmp14, 8); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp13, 2); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 3); qqbar_sub_si(tmp27, tmp27, 4); qqbar_mul_si(tmp27, tmp27, 3); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 85); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 122); qqbar_sqrt_ui(tmp26, 2); qqbar_neg(tmp26, tmp26); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 7); qqbar_sub_si(tmp26, tmp26, 10); qqbar_mul_si(tmp26, tmp26, 11); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 630); qqbar_add(tmp22, tmp23, tmp24); qqbar_sub_si(tmp22, tmp22, 890); qqbar_mul_si(tmp22, tmp22, 2); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_add(tmp23, tmp24, tmp25); qqbar_sub_si(tmp23, tmp23, 3); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 4896); qqbar_sub_si(tmp22, tmp22, 6923); qqbar_mul_si(tmp22, tmp22, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 79); qqbar_sub_si(tmp24, tmp24, 112); qqbar_mul_si(tmp24, tmp24, 20); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 27); qqbar_sub_si(tmp27, tmp27, 38); qqbar_mul_si(tmp27, tmp27, 7); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 342); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 484); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 2820); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 3992); qqbar_sqrt_ui(tmp22, 2); qqbar_neg(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 2); qqbar_sub_si(tmp31, tmp31, 3); qqbar_mul_si(tmp31, tmp31, 3); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, -17); qqbar_add_si(tmp32, tmp32, 26); qqbar_sqrt(tmp32, tmp32); qqbar_mul(tmp30, tmp31, tmp32); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 61); qqbar_sub(tmp29, tmp30, tmp31); qqbar_add_si(tmp29, tmp29, 85); qqbar_sqrt_ui(tmp30, 2); qqbar_neg(tmp30, tmp30); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, 5); qqbar_sub_si(tmp30, tmp30, 7); qqbar_mul_si(tmp30, tmp30, 11); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, -17); qqbar_add_si(tmp31, tmp31, 26); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sub(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 445); qqbar_add(tmp26, tmp27, tmp28); qqbar_sub_si(tmp26, tmp26, 630); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, -17); qqbar_add_si(tmp29, tmp29, 26); qqbar_sqrt(tmp29, tmp29); qqbar_add(tmp27, tmp28, tmp29); qqbar_sub_si(tmp27, tmp27, 3); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_sub_si(tmp26, tmp26, 1); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 89); qqbar_sub_si(tmp26, tmp26, 126); qqbar_mul_si(tmp26, tmp26, 10); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 61); qqbar_sub_si(tmp28, tmp28, 85); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 2); qqbar_sub_si(tmp31, tmp31, 3); qqbar_sqrt_ui(tmp32, 2); qqbar_add_si(tmp32, tmp32, 2); qqbar_sqrt(tmp32, tmp32); qqbar_mul(tmp30, tmp31, tmp32); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 2); qqbar_sub(tmp29, tmp30, tmp31); qqbar_add_si(tmp29, tmp29, 3); qqbar_mul_si(tmp29, tmp29, 3); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, -17); qqbar_add_si(tmp30, tmp30, 26); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sub(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 61); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 85); qqbar_mul_si(tmp25, tmp25, 2); qqbar_sqrt_ui(tmp26, 2); qqbar_neg(tmp26, tmp26); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_add(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 5); qqbar_sub_si(tmp26, tmp26, 7); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 5); qqbar_sub(tmp24, tmp25, tmp26); qqbar_add_si(tmp24, tmp24, 7); qqbar_mul_si(tmp24, tmp24, 22); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_add(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 890); qqbar_add(tmp20, tmp21, tmp22); qqbar_sub_si(tmp20, tmp20, 1260); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -12); qqbar_sqrt_ui(tmp24, 2); qqbar_neg(tmp24, tmp24); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul_si(tmp24, tmp24, 2); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul_si(tmp23, tmp23, 2); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 24); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_add(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 319); qqbar_sub_si(tmp21, tmp21, 452); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 561); qqbar_sub(tmp19, tmp20, tmp21); qqbar_add_si(tmp19, tmp19, 794); qqbar_mul_si(tmp19, tmp19, 4); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_add(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 17064); qqbar_add(tmp15, tmp16, tmp17); qqbar_sub_si(tmp15, tmp15, 24132); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 1); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub_si(tmp19, tmp19, 1); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_add(tmp16, tmp17, tmp18); qqbar_add_si(tmp16, tmp16, 1); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 1); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub_si(tmp19, tmp19, 1); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp24, 2); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_add(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_sub_si(tmp24, tmp24, 1); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 3); qqbar_add(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul_si(tmp22, tmp22, 5); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 8); qqbar_sqrt_ui(tmp25, 2); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_add(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_sub_si(tmp25, tmp25, 1); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul_si(tmp23, tmp23, 5); qqbar_add(tmp21, tmp22, tmp23); qqbar_sub_si(tmp21, tmp21, 8); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 1); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub_si(tmp23, tmp23, 1); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_add(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 1); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_sub_si(tmp21, tmp21, 2); qqbar_pow_ui(tmp21, tmp21, 3); qqbar_mul(tmp19, tmp20, tmp21); qqbar_div(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sub_si(tmp15, tmp15, 1); qqbar_mul(tmp13, tmp14, tmp15); qqbar_set_si(tmp17, 1); qqbar_div_si(tmp17, tmp17, 4); qqbar_neg(tmp17, tmp17); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_set_si(tmp17, 1); qqbar_div_si(tmp17, tmp17, 2); qqbar_add(tmp15, tmp16, tmp17); qqbar_set_si(tmp16, 3); qqbar_div_si(tmp16, tmp16, 2); qqbar_pow(tmp14, tmp15, tmp16); qqbar_mul(tmp12, tmp13, tmp14); qqbar_div(tmp10, tmp11, tmp12); qqbar_add(tmp8, tmp9, tmp10); qqbar_mul(tmp6, tmp7, tmp8); qqbar_sqrt_ui(tmp7, 2); qqbar_add_si(tmp7, tmp7, 2); qqbar_sqrt(tmp7, tmp7); qqbar_sub_si(tmp7, tmp7, 2); qqbar_div(tmp5, tmp6, tmp7); qqbar_add(tmp3, tmp4, tmp5); qqbar_mul(tmp1, tmp2, tmp3); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 3); qqbar_sub_si(tmp14, tmp14, 4); qqbar_mul_si(tmp14, tmp14, 3); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, -17); qqbar_add_si(tmp15, tmp15, 26); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 85); qqbar_sub(tmp12, tmp13, tmp14); qqbar_add_si(tmp12, tmp12, 122); qqbar_sqrt_ui(tmp13, 2); qqbar_neg(tmp13, tmp13); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, 7); qqbar_sub_si(tmp13, tmp13, 10); qqbar_mul_si(tmp13, tmp13, 11); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, -17); qqbar_add_si(tmp14, tmp14, 26); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sub(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, 630); qqbar_add(tmp9, tmp10, tmp11); qqbar_sub_si(tmp9, tmp9, 890); qqbar_mul_si(tmp9, tmp9, 2); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, 3); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, -17); qqbar_add_si(tmp12, tmp12, 26); qqbar_sqrt(tmp12, tmp12); qqbar_add(tmp10, tmp11, tmp12); qqbar_sub_si(tmp10, tmp10, 3); qqbar_sqrt(tmp10, tmp10); qqbar_mul(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp9, 2); qqbar_add_si(tmp9, tmp9, 2); qqbar_sqrt(tmp9, tmp9); qqbar_sub_si(tmp9, tmp9, 1); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp9, 2); qqbar_mul_si(tmp9, tmp9, 4896); qqbar_sub_si(tmp9, tmp9, 6923); qqbar_mul_si(tmp9, tmp9, 2); qqbar_sqrt_ui(tmp10, 2); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_mul(tmp8, tmp9, tmp10); qqbar_sub(tmp6, tmp7, tmp8); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, 79); qqbar_sub_si(tmp11, tmp11, 112); qqbar_mul_si(tmp11, tmp11, 20); qqbar_sqrt_ui(tmp12, 2); qqbar_add_si(tmp12, tmp12, 2); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 27); qqbar_sub_si(tmp14, tmp14, 38); qqbar_mul_si(tmp14, tmp14, 7); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 342); qqbar_sub(tmp12, tmp13, tmp14); qqbar_add_si(tmp12, tmp12, 484); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, -17); qqbar_add_si(tmp13, tmp13, 26); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sub(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 2820); qqbar_sub(tmp8, tmp9, tmp10); qqbar_add_si(tmp8, tmp8, 3992); qqbar_sqrt_ui(tmp9, 2); qqbar_neg(tmp9, tmp9); qqbar_add_si(tmp9, tmp9, 2); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_add(tmp5, tmp6, tmp7); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 2); qqbar_sub_si(tmp18, tmp18, 3); qqbar_mul_si(tmp18, tmp18, 3); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 61); qqbar_sub(tmp16, tmp17, tmp18); qqbar_add_si(tmp16, tmp16, 85); qqbar_sqrt_ui(tmp17, 2); qqbar_neg(tmp17, tmp17); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 5); qqbar_sub_si(tmp17, tmp17, 7); qqbar_mul_si(tmp17, tmp17, 11); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, -17); qqbar_add_si(tmp18, tmp18, 26); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sub(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 445); qqbar_add(tmp13, tmp14, tmp15); qqbar_sub_si(tmp13, tmp13, 630); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 3); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, -17); qqbar_add_si(tmp16, tmp16, 26); qqbar_sqrt(tmp16, tmp16); qqbar_add(tmp14, tmp15, tmp16); qqbar_sub_si(tmp14, tmp14, 3); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp13, 2); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_sub_si(tmp13, tmp13, 1); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, 89); qqbar_sub_si(tmp13, tmp13, 126); qqbar_mul_si(tmp13, tmp13, 10); qqbar_sqrt_ui(tmp14, 2); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sub(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 61); qqbar_sub_si(tmp15, tmp15, 85); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 2); qqbar_sub_si(tmp18, tmp18, 3); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 2); qqbar_sub(tmp16, tmp17, tmp18); qqbar_add_si(tmp16, tmp16, 3); qqbar_mul_si(tmp16, tmp16, 3); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, -17); qqbar_add_si(tmp17, tmp17, 26); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sub(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 61); qqbar_sub(tmp12, tmp13, tmp14); qqbar_add_si(tmp12, tmp12, 85); qqbar_mul_si(tmp12, tmp12, 2); qqbar_sqrt_ui(tmp13, 2); qqbar_neg(tmp13, tmp13); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_add(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, 5); qqbar_sub_si(tmp13, tmp13, 7); qqbar_sqrt_ui(tmp14, 2); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, 5); qqbar_sub(tmp11, tmp12, tmp13); qqbar_add_si(tmp11, tmp11, 7); qqbar_mul_si(tmp11, tmp11, 22); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, -17); qqbar_add_si(tmp12, tmp12, 26); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_add(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp9, 2); qqbar_mul_si(tmp9, tmp9, 890); qqbar_add(tmp7, tmp8, tmp9); qqbar_sub_si(tmp7, tmp7, 1260); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, -12); qqbar_sqrt_ui(tmp11, 2); qqbar_neg(tmp11, tmp11); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_mul_si(tmp11, tmp11, 2); qqbar_sub(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, -17); qqbar_add_si(tmp10, tmp10, 26); qqbar_sqrt(tmp10, tmp10); qqbar_mul_si(tmp10, tmp10, 2); qqbar_sub(tmp8, tmp9, tmp10); qqbar_add_si(tmp8, tmp8, 24); qqbar_sqrt(tmp8, tmp8); qqbar_mul(tmp6, tmp7, tmp8); qqbar_add(tmp4, tmp5, tmp6); qqbar_sqrt_ui(tmp8, 2); qqbar_mul_si(tmp8, tmp8, 319); qqbar_sub_si(tmp8, tmp8, 452); qqbar_sqrt_ui(tmp9, 2); qqbar_add_si(tmp9, tmp9, 2); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp8, 2); qqbar_mul_si(tmp8, tmp8, 561); qqbar_sub(tmp6, tmp7, tmp8); qqbar_add_si(tmp6, tmp6, 794); qqbar_mul_si(tmp6, tmp6, 4); qqbar_sqrt_ui(tmp7, 2); qqbar_mul_si(tmp7, tmp7, -17); qqbar_add_si(tmp7, tmp7, 26); qqbar_sqrt(tmp7, tmp7); qqbar_mul(tmp5, tmp6, tmp7); qqbar_add(tmp3, tmp4, tmp5); qqbar_sqrt_ui(tmp4, 2); qqbar_mul_si(tmp4, tmp4, 17064); qqbar_add(tmp2, tmp3, tmp4); qqbar_sub_si(tmp2, tmp2, 24132); qqbar_div(tmp0, tmp1, tmp2); qqbar_set_si(tmp4, 1); qqbar_div_si(tmp4, tmp4, 16); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, 89); qqbar_sub_si(tmp12, tmp12, 126); qqbar_mul_si(tmp12, tmp12, 5); qqbar_sqrt_ui(tmp13, 2); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 61); qqbar_sub_si(tmp16, tmp16, 85); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sub_si(tmp19, tmp19, 3); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 4); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 6); qqbar_mul_si(tmp17, tmp17, 3); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, -17); qqbar_add_si(tmp18, tmp18, 26); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sub(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 122); qqbar_sub(tmp13, tmp14, tmp15); qqbar_add_si(tmp13, tmp13, 170); qqbar_sqrt_ui(tmp14, 2); qqbar_neg(tmp14, tmp14); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sub(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 5); qqbar_sub_si(tmp14, tmp14, 7); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 10); qqbar_sub(tmp12, tmp13, tmp14); qqbar_add_si(tmp12, tmp12, 14); qqbar_mul_si(tmp12, tmp12, 11); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, -17); qqbar_add_si(tmp13, tmp13, 26); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sub(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 890); qqbar_sub(tmp8, tmp9, tmp10); qqbar_add_si(tmp8, tmp8, 1260); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 3); qqbar_sqrt_ui(tmp11, 2); qqbar_neg(tmp11, tmp11); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_add(tmp9, tmp10, tmp11); qqbar_sub_si(tmp9, tmp9, 5); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, -12); qqbar_sqrt_ui(tmp11, 2); qqbar_neg(tmp11, tmp11); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_mul_si(tmp11, tmp11, 2); qqbar_sub(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, -17); qqbar_add_si(tmp10, tmp10, 26); qqbar_sqrt(tmp10, tmp10); qqbar_mul_si(tmp10, tmp10, 2); qqbar_sub(tmp8, tmp9, tmp10); qqbar_add_si(tmp8, tmp8, 24); qqbar_sqrt(tmp8, tmp8); qqbar_mul(tmp6, tmp7, tmp8); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, 63); qqbar_sub_si(tmp12, tmp12, 89); qqbar_mul_si(tmp12, tmp12, 10); qqbar_sqrt_ui(tmp13, 2); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 85); qqbar_sub_si(tmp16, tmp16, 122); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 3); qqbar_sub_si(tmp19, tmp19, 4); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 6); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 8); qqbar_mul_si(tmp17, tmp17, 3); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, -17); qqbar_add_si(tmp18, tmp18, 26); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sub(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 170); qqbar_sub(tmp13, tmp14, tmp15); qqbar_add_si(tmp13, tmp13, 244); qqbar_sqrt_ui(tmp14, 2); qqbar_neg(tmp14, tmp14); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sub(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 7); qqbar_sub_si(tmp14, tmp14, 10); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 14); qqbar_sub(tmp12, tmp13, tmp14); qqbar_add_si(tmp12, tmp12, 20); qqbar_mul_si(tmp12, tmp12, 11); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, -17); qqbar_add_si(tmp13, tmp13, 26); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sub(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 1260); qqbar_sub(tmp8, tmp9, tmp10); qqbar_add_si(tmp8, tmp8, 1780); qqbar_mul_si(tmp8, tmp8, 2); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 3); qqbar_sqrt_ui(tmp11, 2); qqbar_neg(tmp11, tmp11); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_add(tmp9, tmp10, tmp11); qqbar_sub_si(tmp9, tmp9, 5); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_add(tmp5, tmp6, tmp7); qqbar_mul(tmp3, tmp4, tmp5); qqbar_sqrt_ui(tmp12, 2); qqbar_sqrt_ui(tmp13, 2); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp12, 2); qqbar_sub(tmp10, tmp11, tmp12); qqbar_sub_si(tmp10, tmp10, 1); qqbar_sqrt_ui(tmp11, 2); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_sub_si(tmp11, tmp11, 1); qqbar_sqrt(tmp11, tmp11); qqbar_mul(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_sub(tmp8, tmp9, tmp10); qqbar_add_si(tmp8, tmp8, 1); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 7); qqbar_sub_si(tmp19, tmp19, 10); qqbar_mul_si(tmp19, tmp19, 44); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 7); qqbar_sub_si(tmp24, tmp24, 10); qqbar_mul_si(tmp24, tmp24, 11); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 63); qqbar_sub_si(tmp24, tmp24, 89); qqbar_mul_si(tmp24, tmp24, 10); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sub(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 3); qqbar_sub_si(tmp26, tmp26, 4); qqbar_mul_si(tmp26, tmp26, 3); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 85); qqbar_sub_si(tmp26, tmp26, 122); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_neg(tmp24, tmp24); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 3); qqbar_sub_si(tmp27, tmp27, 4); qqbar_mul_si(tmp27, tmp27, 3); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 85); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 122); qqbar_sqrt_ui(tmp26, 2); qqbar_neg(tmp26, tmp26); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 7); qqbar_sub_si(tmp26, tmp26, 10); qqbar_mul_si(tmp26, tmp26, 11); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 630); qqbar_add(tmp22, tmp23, tmp24); qqbar_sub_si(tmp22, tmp22, 890); qqbar_mul_si(tmp22, tmp22, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub_si(tmp23, tmp23, 1); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 3); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_add(tmp20, tmp21, tmp22); qqbar_sub_si(tmp20, tmp20, 3); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 63); qqbar_sub_si(tmp18, tmp18, 89); qqbar_mul_si(tmp18, tmp18, 40); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 3); qqbar_sub_si(tmp20, tmp20, 4); qqbar_mul_si(tmp20, tmp20, 3); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 85); qqbar_sub_si(tmp20, tmp20, 122); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sub(tmp17, tmp18, tmp19); qqbar_mul_si(tmp17, tmp17, 4); qqbar_sqrt_ui(tmp18, 2); qqbar_neg(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sub(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 5); qqbar_sub_si(tmp22, tmp22, 7); qqbar_mul_si(tmp22, tmp22, 22); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 5); qqbar_sub_si(tmp27, tmp27, 7); qqbar_mul_si(tmp27, tmp27, 11); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 89); qqbar_sub_si(tmp27, tmp27, 126); qqbar_mul_si(tmp27, tmp27, 5); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sub(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 2); qqbar_sub_si(tmp29, tmp29, 3); qqbar_mul_si(tmp29, tmp29, 3); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, -17); qqbar_add_si(tmp29, tmp29, 26); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 61); qqbar_sub_si(tmp29, tmp29, 85); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sub(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_neg(tmp27, tmp27); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, 2); qqbar_sub_si(tmp30, tmp30, 3); qqbar_mul_si(tmp30, tmp30, 3); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, -17); qqbar_add_si(tmp31, tmp31, 26); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, 61); qqbar_sub(tmp28, tmp29, tmp30); qqbar_add_si(tmp28, tmp28, 85); qqbar_sqrt_ui(tmp29, 2); qqbar_neg(tmp29, tmp29); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 5); qqbar_sub_si(tmp29, tmp29, 7); qqbar_mul_si(tmp29, tmp29, 11); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, -17); qqbar_add_si(tmp30, tmp30, 26); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sub(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 445); qqbar_add(tmp25, tmp26, tmp27); qqbar_sub_si(tmp25, tmp25, 630); qqbar_mul_si(tmp25, tmp25, 2); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_sub_si(tmp26, tmp26, 1); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_add(tmp23, tmp24, tmp25); qqbar_sub_si(tmp23, tmp23, 3); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 89); qqbar_sub_si(tmp21, tmp21, 126); qqbar_mul_si(tmp21, tmp21, 10); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 2); qqbar_sub_si(tmp23, tmp23, 3); qqbar_mul_si(tmp23, tmp23, 3); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 61); qqbar_sub_si(tmp23, tmp23, 85); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_mul_si(tmp20, tmp20, 2); qqbar_sqrt_ui(tmp21, 2); qqbar_neg(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 2); qqbar_sub_si(tmp24, tmp24, 3); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 61); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 85); qqbar_sqrt_ui(tmp23, 2); qqbar_neg(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 5); qqbar_sub_si(tmp23, tmp23, 7); qqbar_mul_si(tmp23, tmp23, 11); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 445); qqbar_add(tmp19, tmp20, tmp21); qqbar_sub_si(tmp19, tmp19, 630); qqbar_mul_si(tmp19, tmp19, 4); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_sub_si(tmp20, tmp20, 1); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -12); qqbar_sqrt_ui(tmp20, 2); qqbar_neg(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul_si(tmp20, tmp20, 2); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 24); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_add(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 3); qqbar_sub_si(tmp20, tmp20, 4); qqbar_mul_si(tmp20, tmp20, 3); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 85); qqbar_sub(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 122); qqbar_sqrt_ui(tmp19, 2); qqbar_neg(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 7); qqbar_sub_si(tmp19, tmp19, 10); qqbar_mul_si(tmp19, tmp19, 11); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 630); qqbar_add(tmp15, tmp16, tmp17); qqbar_sub_si(tmp15, tmp15, 890); qqbar_mul_si(tmp15, tmp15, 8); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_sub_si(tmp16, tmp16, 1); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sub(tmp12, tmp13, tmp14); qqbar_mul_si(tmp12, tmp12, 8); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_add_si(tmp16, tmp16, 1); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_sub_si(tmp17, tmp17, 1); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_add(tmp14, tmp15, tmp16); qqbar_add_si(tmp14, tmp14, 1); qqbar_si_div(tmp14, 1, tmp14); qqbar_sqrt_ui(tmp22, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_add(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 3); qqbar_add(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul_si(tmp20, tmp20, 5); qqbar_sub(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 8); qqbar_sqrt_ui(tmp23, 2); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_add(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub_si(tmp23, tmp23, 1); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 3); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul_si(tmp21, tmp21, 5); qqbar_add(tmp19, tmp20, tmp21); qqbar_sub_si(tmp19, tmp19, 8); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 2); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 1); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_add(tmp19, tmp20, tmp21); qqbar_add_si(tmp19, tmp19, 1); qqbar_pow_ui(tmp19, tmp19, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 1); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_sub_si(tmp24, tmp24, 1); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp29, 2); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_add(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_sub_si(tmp29, tmp29, 1); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 3); qqbar_add(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul_si(tmp27, tmp27, 5); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 8); qqbar_sqrt_ui(tmp30, 2); qqbar_sqrt_ui(tmp31, 2); qqbar_add_si(tmp31, tmp31, 2); qqbar_sqrt(tmp31, tmp31); qqbar_add(tmp29, tmp30, tmp31); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_sub_si(tmp30, tmp30, 1); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 3); qqbar_sub(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul_si(tmp28, tmp28, 5); qqbar_add(tmp26, tmp27, tmp28); qqbar_sub_si(tmp26, tmp26, 8); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_add_si(tmp25, tmp25, 2); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_add_si(tmp27, tmp27, 1); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_sub_si(tmp28, tmp28, 1); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_add(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 1); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_sub_si(tmp26, tmp26, 2); qqbar_pow_ui(tmp26, tmp26, 3); qqbar_mul(tmp24, tmp25, tmp26); qqbar_div(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sub_si(tmp20, tmp20, 1); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub_si(tmp19, tmp19, 2); qqbar_pow_ui(tmp19, tmp19, 3); qqbar_mul(tmp17, tmp18, tmp19); qqbar_div(tmp15, tmp16, tmp17); qqbar_add(tmp13, tmp14, tmp15); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sub_si(tmp24, tmp24, 4); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 85); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 122); qqbar_sqrt_ui(tmp23, 2); qqbar_neg(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 7); qqbar_sub_si(tmp23, tmp23, 10); qqbar_mul_si(tmp23, tmp23, 11); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 630); qqbar_add(tmp19, tmp20, tmp21); qqbar_sub_si(tmp19, tmp19, 890); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 3); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_add(tmp20, tmp21, tmp22); qqbar_sub_si(tmp20, tmp20, 3); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub_si(tmp19, tmp19, 1); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 4896); qqbar_sub_si(tmp19, tmp19, 6923); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 79); qqbar_sub_si(tmp21, tmp21, 112); qqbar_mul_si(tmp21, tmp21, 20); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 27); qqbar_sub_si(tmp24, tmp24, 38); qqbar_mul_si(tmp24, tmp24, 7); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 342); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 484); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 2820); qqbar_sub(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 3992); qqbar_sqrt_ui(tmp19, 2); qqbar_neg(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_add(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 2); qqbar_sub_si(tmp28, tmp28, 3); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, -17); qqbar_add_si(tmp29, tmp29, 26); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 61); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 85); qqbar_sqrt_ui(tmp27, 2); qqbar_neg(tmp27, tmp27); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 5); qqbar_sub_si(tmp27, tmp27, 7); qqbar_mul_si(tmp27, tmp27, 11); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sub(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 445); qqbar_add(tmp23, tmp24, tmp25); qqbar_sub_si(tmp23, tmp23, 630); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_add(tmp24, tmp25, tmp26); qqbar_sub_si(tmp24, tmp24, 3); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub_si(tmp23, tmp23, 1); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 89); qqbar_sub_si(tmp23, tmp23, 126); qqbar_mul_si(tmp23, tmp23, 10); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 61); qqbar_sub_si(tmp25, tmp25, 85); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 2); qqbar_sub_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 2); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 3); qqbar_mul_si(tmp26, tmp26, 3); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 61); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 85); qqbar_mul_si(tmp22, tmp22, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_neg(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_add(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 5); qqbar_sub_si(tmp23, tmp23, 7); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 5); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 7); qqbar_mul_si(tmp21, tmp21, 22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 890); qqbar_add(tmp17, tmp18, tmp19); qqbar_sub_si(tmp17, tmp17, 1260); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -12); qqbar_sqrt_ui(tmp21, 2); qqbar_neg(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul_si(tmp21, tmp21, 2); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul_si(tmp20, tmp20, 2); qqbar_sub(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 24); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_add(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 319); qqbar_sub_si(tmp18, tmp18, 452); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 561); qqbar_sub(tmp16, tmp17, tmp18); qqbar_add_si(tmp16, tmp16, 794); qqbar_mul_si(tmp16, tmp16, 4); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, -17); qqbar_add_si(tmp17, tmp17, 26); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_add(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 17064); qqbar_add(tmp12, tmp13, tmp14); qqbar_sub_si(tmp12, tmp12, 24132); qqbar_div(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 89); qqbar_sub_si(tmp21, tmp21, 126); qqbar_mul_si(tmp21, tmp21, 5); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 61); qqbar_sub_si(tmp25, tmp25, 85); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 2); qqbar_sub_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 4); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 6); qqbar_mul_si(tmp26, tmp26, 3); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 122); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 170); qqbar_sqrt_ui(tmp23, 2); qqbar_neg(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 5); qqbar_sub_si(tmp23, tmp23, 7); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 10); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 14); qqbar_mul_si(tmp21, tmp21, 11); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 890); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 1260); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 3); qqbar_sqrt_ui(tmp20, 2); qqbar_neg(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_add(tmp18, tmp19, tmp20); qqbar_sub_si(tmp18, tmp18, 5); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -12); qqbar_sqrt_ui(tmp20, 2); qqbar_neg(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul_si(tmp20, tmp20, 2); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 24); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 63); qqbar_sub_si(tmp21, tmp21, 89); qqbar_mul_si(tmp21, tmp21, 10); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 85); qqbar_sub_si(tmp25, tmp25, 122); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sub_si(tmp28, tmp28, 4); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 6); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 8); qqbar_mul_si(tmp26, tmp26, 3); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 170); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 244); qqbar_sqrt_ui(tmp23, 2); qqbar_neg(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 7); qqbar_sub_si(tmp23, tmp23, 10); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 14); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 20); qqbar_mul_si(tmp21, tmp21, 11); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 1260); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 1780); qqbar_mul_si(tmp17, tmp17, 2); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 3); qqbar_sqrt_ui(tmp20, 2); qqbar_neg(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_add(tmp18, tmp19, tmp20); qqbar_sub_si(tmp18, tmp18, 5); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_add(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp19, 2); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub_si(tmp19, tmp19, 1); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 3); qqbar_add(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_mul_si(tmp17, tmp17, 5); qqbar_sub(tmp15, tmp16, tmp17); qqbar_add_si(tmp15, tmp15, 8); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sub_si(tmp28, tmp28, 4); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, -17); qqbar_add_si(tmp29, tmp29, 26); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 85); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 122); qqbar_sqrt_ui(tmp27, 2); qqbar_neg(tmp27, tmp27); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 7); qqbar_sub_si(tmp27, tmp27, 10); qqbar_mul_si(tmp27, tmp27, 11); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sub(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 630); qqbar_add(tmp23, tmp24, tmp25); qqbar_sub_si(tmp23, tmp23, 890); qqbar_mul_si(tmp23, tmp23, 2); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_add(tmp24, tmp25, tmp26); qqbar_sub_si(tmp24, tmp24, 3); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub_si(tmp23, tmp23, 1); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 4896); qqbar_sub_si(tmp23, tmp23, 6923); qqbar_mul_si(tmp23, tmp23, 2); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 79); qqbar_sub_si(tmp25, tmp25, 112); qqbar_mul_si(tmp25, tmp25, 20); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 27); qqbar_sub_si(tmp28, tmp28, 38); qqbar_mul_si(tmp28, tmp28, 7); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 342); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 484); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 2820); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 3992); qqbar_sqrt_ui(tmp23, 2); qqbar_neg(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_add(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, 2); qqbar_sub_si(tmp32, tmp32, 3); qqbar_mul_si(tmp32, tmp32, 3); qqbar_sqrt_ui(tmp33, 2); qqbar_mul_si(tmp33, tmp33, -17); qqbar_add_si(tmp33, tmp33, 26); qqbar_sqrt(tmp33, tmp33); qqbar_mul(tmp31, tmp32, tmp33); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, 61); qqbar_sub(tmp30, tmp31, tmp32); qqbar_add_si(tmp30, tmp30, 85); qqbar_sqrt_ui(tmp31, 2); qqbar_neg(tmp31, tmp31); qqbar_add_si(tmp31, tmp31, 2); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 5); qqbar_sub_si(tmp31, tmp31, 7); qqbar_mul_si(tmp31, tmp31, 11); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, -17); qqbar_add_si(tmp32, tmp32, 26); qqbar_sqrt(tmp32, tmp32); qqbar_mul(tmp30, tmp31, tmp32); qqbar_sub(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 445); qqbar_add(tmp27, tmp28, tmp29); qqbar_sub_si(tmp27, tmp27, 630); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 3); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, -17); qqbar_add_si(tmp30, tmp30, 26); qqbar_sqrt(tmp30, tmp30); qqbar_add(tmp28, tmp29, tmp30); qqbar_sub_si(tmp28, tmp28, 3); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_sub_si(tmp27, tmp27, 1); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 89); qqbar_sub_si(tmp27, tmp27, 126); qqbar_mul_si(tmp27, tmp27, 10); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sub(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 61); qqbar_sub_si(tmp29, tmp29, 85); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, 2); qqbar_sub_si(tmp32, tmp32, 3); qqbar_sqrt_ui(tmp33, 2); qqbar_add_si(tmp33, tmp33, 2); qqbar_sqrt(tmp33, tmp33); qqbar_mul(tmp31, tmp32, tmp33); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, 2); qqbar_sub(tmp30, tmp31, tmp32); qqbar_add_si(tmp30, tmp30, 3); qqbar_mul_si(tmp30, tmp30, 3); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, -17); qqbar_add_si(tmp31, tmp31, 26); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sub(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 61); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 85); qqbar_mul_si(tmp26, tmp26, 2); qqbar_sqrt_ui(tmp27, 2); qqbar_neg(tmp27, tmp27); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_add(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 5); qqbar_sub_si(tmp27, tmp27, 7); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 5); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 7); qqbar_mul_si(tmp25, tmp25, 22); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_add(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 890); qqbar_add(tmp21, tmp22, tmp23); qqbar_sub_si(tmp21, tmp21, 1260); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -12); qqbar_sqrt_ui(tmp25, 2); qqbar_neg(tmp25, tmp25); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul_si(tmp25, tmp25, 2); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul_si(tmp24, tmp24, 2); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 24); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 319); qqbar_sub_si(tmp22, tmp22, 452); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 561); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 794); qqbar_mul_si(tmp20, tmp20, 4); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_add(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 17064); qqbar_add(tmp16, tmp17, tmp18); qqbar_sub_si(tmp16, tmp16, 24132); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 1); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_sub_si(tmp20, tmp20, 1); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_add(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 1); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 1); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_sub_si(tmp20, tmp20, 1); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp25, 2); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_add(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_sub_si(tmp25, tmp25, 1); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 3); qqbar_add(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul_si(tmp23, tmp23, 5); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 8); qqbar_sqrt_ui(tmp26, 2); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_add(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_sub_si(tmp26, tmp26, 1); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul_si(tmp24, tmp24, 5); qqbar_add(tmp22, tmp23, tmp24); qqbar_sub_si(tmp22, tmp22, 8); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 2); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 1); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_sub_si(tmp24, tmp24, 1); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_add(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 1); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 2); qqbar_pow_ui(tmp22, tmp22, 3); qqbar_mul(tmp20, tmp21, tmp22); qqbar_div(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sub_si(tmp16, tmp16, 1); qqbar_mul(tmp14, tmp15, tmp16); qqbar_set_si(tmp18, 1); qqbar_div_si(tmp18, tmp18, 4); qqbar_neg(tmp18, tmp18); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_set_si(tmp18, 1); qqbar_div_si(tmp18, tmp18, 2); qqbar_add(tmp16, tmp17, tmp18); qqbar_set_si(tmp17, 3); qqbar_div_si(tmp17, tmp17, 2); qqbar_pow(tmp15, tmp16, tmp17); qqbar_mul(tmp13, tmp14, tmp15); qqbar_div(tmp11, tmp12, tmp13); qqbar_add(tmp9, tmp10, tmp11); qqbar_mul(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp8, 2); qqbar_add_si(tmp8, tmp8, 2); qqbar_sqrt(tmp8, tmp8); qqbar_add_si(tmp8, tmp8, 2); qqbar_sqrt(tmp8, tmp8); qqbar_mul(tmp6, tmp7, tmp8); qqbar_set_si(tmp9, 1); qqbar_div_si(tmp9, tmp9, 4); qqbar_neg(tmp9, tmp9); qqbar_sqrt_ui(tmp10, 2); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_mul(tmp8, tmp9, tmp10); qqbar_set_si(tmp9, 1); qqbar_div_si(tmp9, tmp9, 2); qqbar_add(tmp7, tmp8, tmp9); qqbar_sqrt(tmp7, tmp7); qqbar_div(tmp5, tmp6, tmp7); qqbar_sqrt_ui(tmp12, 2); qqbar_add_si(tmp12, tmp12, 2); qqbar_sqrt(tmp12, tmp12); qqbar_sqrt_ui(tmp13, 2); qqbar_sub_si(tmp13, tmp13, 1); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp12, 2); qqbar_add_si(tmp12, tmp12, 2); qqbar_sqrt(tmp12, tmp12); qqbar_sub_si(tmp12, tmp12, 1); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp11, 2); qqbar_add(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_sub(tmp8, tmp9, tmp10); qqbar_mul_si(tmp8, tmp8, 2); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 89); qqbar_sub_si(tmp19, tmp19, 126); qqbar_mul_si(tmp19, tmp19, 5); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 61); qqbar_sub_si(tmp23, tmp23, 85); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 2); qqbar_sub_si(tmp26, tmp26, 3); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 4); qqbar_sub(tmp24, tmp25, tmp26); qqbar_add_si(tmp24, tmp24, 6); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sub(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 122); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 170); qqbar_sqrt_ui(tmp21, 2); qqbar_neg(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 5); qqbar_sub_si(tmp21, tmp21, 7); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 10); qqbar_sub(tmp19, tmp20, tmp21); qqbar_add_si(tmp19, tmp19, 14); qqbar_mul_si(tmp19, tmp19, 11); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 890); qqbar_sub(tmp15, tmp16, tmp17); qqbar_add_si(tmp15, tmp15, 1260); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 3); qqbar_sqrt_ui(tmp18, 2); qqbar_neg(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_add(tmp16, tmp17, tmp18); qqbar_sub_si(tmp16, tmp16, 5); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, -12); qqbar_sqrt_ui(tmp18, 2); qqbar_neg(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul_si(tmp18, tmp18, 2); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, -17); qqbar_add_si(tmp17, tmp17, 26); qqbar_sqrt(tmp17, tmp17); qqbar_mul_si(tmp17, tmp17, 2); qqbar_sub(tmp15, tmp16, tmp17); qqbar_add_si(tmp15, tmp15, 24); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 63); qqbar_sub_si(tmp19, tmp19, 89); qqbar_mul_si(tmp19, tmp19, 10); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 85); qqbar_sub_si(tmp23, tmp23, 122); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 3); qqbar_sub_si(tmp26, tmp26, 4); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 6); qqbar_sub(tmp24, tmp25, tmp26); qqbar_add_si(tmp24, tmp24, 8); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sub(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 170); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 244); qqbar_sqrt_ui(tmp21, 2); qqbar_neg(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 7); qqbar_sub_si(tmp21, tmp21, 10); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 14); qqbar_sub(tmp19, tmp20, tmp21); qqbar_add_si(tmp19, tmp19, 20); qqbar_mul_si(tmp19, tmp19, 11); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 1260); qqbar_sub(tmp15, tmp16, tmp17); qqbar_add_si(tmp15, tmp15, 1780); qqbar_mul_si(tmp15, tmp15, 2); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, 3); qqbar_sqrt_ui(tmp18, 2); qqbar_neg(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_add(tmp16, tmp17, tmp18); qqbar_sub_si(tmp16, tmp16, 5); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_add(tmp12, tmp13, tmp14); qqbar_mul_si(tmp12, tmp12, 8); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_add_si(tmp16, tmp16, 1); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_sub_si(tmp17, tmp17, 1); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_add(tmp14, tmp15, tmp16); qqbar_add_si(tmp14, tmp14, 1); qqbar_si_div(tmp14, 1, tmp14); qqbar_sqrt_ui(tmp22, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_add(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 3); qqbar_add(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul_si(tmp20, tmp20, 5); qqbar_sub(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 8); qqbar_sqrt_ui(tmp23, 2); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_add(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub_si(tmp23, tmp23, 1); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 3); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul_si(tmp21, tmp21, 5); qqbar_add(tmp19, tmp20, tmp21); qqbar_sub_si(tmp19, tmp19, 8); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 2); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 1); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_add(tmp19, tmp20, tmp21); qqbar_add_si(tmp19, tmp19, 1); qqbar_pow_ui(tmp19, tmp19, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 1); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_sub_si(tmp24, tmp24, 1); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp29, 2); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_add(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_sub_si(tmp29, tmp29, 1); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 3); qqbar_add(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul_si(tmp27, tmp27, 5); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 8); qqbar_sqrt_ui(tmp30, 2); qqbar_sqrt_ui(tmp31, 2); qqbar_add_si(tmp31, tmp31, 2); qqbar_sqrt(tmp31, tmp31); qqbar_add(tmp29, tmp30, tmp31); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_sub_si(tmp30, tmp30, 1); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 3); qqbar_sub(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul_si(tmp28, tmp28, 5); qqbar_add(tmp26, tmp27, tmp28); qqbar_sub_si(tmp26, tmp26, 8); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_add_si(tmp25, tmp25, 2); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_add_si(tmp27, tmp27, 1); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_sub_si(tmp28, tmp28, 1); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_add(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 1); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_sub_si(tmp26, tmp26, 2); qqbar_pow_ui(tmp26, tmp26, 3); qqbar_mul(tmp24, tmp25, tmp26); qqbar_div(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sub_si(tmp20, tmp20, 1); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub_si(tmp19, tmp19, 2); qqbar_pow_ui(tmp19, tmp19, 3); qqbar_mul(tmp17, tmp18, tmp19); qqbar_div(tmp15, tmp16, tmp17); qqbar_add(tmp13, tmp14, tmp15); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sub_si(tmp24, tmp24, 4); qqbar_mul_si(tmp24, tmp24, 3); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 85); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 122); qqbar_sqrt_ui(tmp23, 2); qqbar_neg(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 7); qqbar_sub_si(tmp23, tmp23, 10); qqbar_mul_si(tmp23, tmp23, 11); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 630); qqbar_add(tmp19, tmp20, tmp21); qqbar_sub_si(tmp19, tmp19, 890); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 3); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_add(tmp20, tmp21, tmp22); qqbar_sub_si(tmp20, tmp20, 3); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub_si(tmp19, tmp19, 1); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 4896); qqbar_sub_si(tmp19, tmp19, 6923); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 79); qqbar_sub_si(tmp21, tmp21, 112); qqbar_mul_si(tmp21, tmp21, 20); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 27); qqbar_sub_si(tmp24, tmp24, 38); qqbar_mul_si(tmp24, tmp24, 7); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 342); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 484); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 2820); qqbar_sub(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 3992); qqbar_sqrt_ui(tmp19, 2); qqbar_neg(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_add(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 2); qqbar_sub_si(tmp28, tmp28, 3); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, -17); qqbar_add_si(tmp29, tmp29, 26); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 61); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 85); qqbar_sqrt_ui(tmp27, 2); qqbar_neg(tmp27, tmp27); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 5); qqbar_sub_si(tmp27, tmp27, 7); qqbar_mul_si(tmp27, tmp27, 11); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sub(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 445); qqbar_add(tmp23, tmp24, tmp25); qqbar_sub_si(tmp23, tmp23, 630); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_add(tmp24, tmp25, tmp26); qqbar_sub_si(tmp24, tmp24, 3); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub_si(tmp23, tmp23, 1); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 89); qqbar_sub_si(tmp23, tmp23, 126); qqbar_mul_si(tmp23, tmp23, 10); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 61); qqbar_sub_si(tmp25, tmp25, 85); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 2); qqbar_sub_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 2); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 3); qqbar_mul_si(tmp26, tmp26, 3); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 61); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 85); qqbar_mul_si(tmp22, tmp22, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_neg(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_add(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 5); qqbar_sub_si(tmp23, tmp23, 7); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 5); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 7); qqbar_mul_si(tmp21, tmp21, 22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 890); qqbar_add(tmp17, tmp18, tmp19); qqbar_sub_si(tmp17, tmp17, 1260); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -12); qqbar_sqrt_ui(tmp21, 2); qqbar_neg(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul_si(tmp21, tmp21, 2); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul_si(tmp20, tmp20, 2); qqbar_sub(tmp18, tmp19, tmp20); qqbar_add_si(tmp18, tmp18, 24); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_add(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 319); qqbar_sub_si(tmp18, tmp18, 452); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 561); qqbar_sub(tmp16, tmp17, tmp18); qqbar_add_si(tmp16, tmp16, 794); qqbar_mul_si(tmp16, tmp16, 4); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, -17); qqbar_add_si(tmp17, tmp17, 26); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_add(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 17064); qqbar_add(tmp12, tmp13, tmp14); qqbar_sub_si(tmp12, tmp12, 24132); qqbar_div(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 7); qqbar_sub_si(tmp21, tmp21, 10); qqbar_mul_si(tmp21, tmp21, 44); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 7); qqbar_sub_si(tmp26, tmp26, 10); qqbar_mul_si(tmp26, tmp26, 11); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 63); qqbar_sub_si(tmp26, tmp26, 89); qqbar_mul_si(tmp26, tmp26, 10); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sub_si(tmp28, tmp28, 4); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 85); qqbar_sub_si(tmp28, tmp28, 122); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sub(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_neg(tmp26, tmp26); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 3); qqbar_sub_si(tmp29, tmp29, 4); qqbar_mul_si(tmp29, tmp29, 3); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, -17); qqbar_add_si(tmp30, tmp30, 26); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 85); qqbar_sub(tmp27, tmp28, tmp29); qqbar_add_si(tmp27, tmp27, 122); qqbar_sqrt_ui(tmp28, 2); qqbar_neg(tmp28, tmp28); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 7); qqbar_sub_si(tmp28, tmp28, 10); qqbar_mul_si(tmp28, tmp28, 11); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, -17); qqbar_add_si(tmp29, tmp29, 26); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sub(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 630); qqbar_add(tmp24, tmp25, tmp26); qqbar_sub_si(tmp24, tmp24, 890); qqbar_mul_si(tmp24, tmp24, 2); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_sub_si(tmp25, tmp25, 1); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_add(tmp21, tmp22, tmp23); qqbar_mul_si(tmp21, tmp21, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 3); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_add(tmp22, tmp23, tmp24); qqbar_sub_si(tmp22, tmp22, 3); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, 63); qqbar_sub_si(tmp20, tmp20, 89); qqbar_mul_si(tmp20, tmp20, 40); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 3); qqbar_sub_si(tmp22, tmp22, 4); qqbar_mul_si(tmp22, tmp22, 3); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 85); qqbar_sub_si(tmp22, tmp22, 122); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_mul_si(tmp19, tmp19, 4); qqbar_sqrt_ui(tmp20, 2); qqbar_neg(tmp20, tmp20); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 5); qqbar_sub_si(tmp24, tmp24, 7); qqbar_mul_si(tmp24, tmp24, 22); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 5); qqbar_sub_si(tmp29, tmp29, 7); qqbar_mul_si(tmp29, tmp29, 11); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, -17); qqbar_add_si(tmp29, tmp29, 26); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 89); qqbar_sub_si(tmp29, tmp29, 126); qqbar_mul_si(tmp29, tmp29, 5); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sub(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 2); qqbar_sub_si(tmp31, tmp31, 3); qqbar_mul_si(tmp31, tmp31, 3); qqbar_sqrt_ui(tmp32, 2); qqbar_add_si(tmp32, tmp32, 2); qqbar_sqrt(tmp32, tmp32); qqbar_mul(tmp30, tmp31, tmp32); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, -17); qqbar_add_si(tmp31, tmp31, 26); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 61); qqbar_sub_si(tmp31, tmp31, 85); qqbar_sqrt_ui(tmp32, 2); qqbar_add_si(tmp32, tmp32, 2); qqbar_sqrt(tmp32, tmp32); qqbar_mul(tmp30, tmp31, tmp32); qqbar_sub(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_neg(tmp29, tmp29); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sub(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, 2); qqbar_sub_si(tmp32, tmp32, 3); qqbar_mul_si(tmp32, tmp32, 3); qqbar_sqrt_ui(tmp33, 2); qqbar_mul_si(tmp33, tmp33, -17); qqbar_add_si(tmp33, tmp33, 26); qqbar_sqrt(tmp33, tmp33); qqbar_mul(tmp31, tmp32, tmp33); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, 61); qqbar_sub(tmp30, tmp31, tmp32); qqbar_add_si(tmp30, tmp30, 85); qqbar_sqrt_ui(tmp31, 2); qqbar_neg(tmp31, tmp31); qqbar_add_si(tmp31, tmp31, 2); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 5); qqbar_sub_si(tmp31, tmp31, 7); qqbar_mul_si(tmp31, tmp31, 11); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, -17); qqbar_add_si(tmp32, tmp32, 26); qqbar_sqrt(tmp32, tmp32); qqbar_mul(tmp30, tmp31, tmp32); qqbar_sub(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 445); qqbar_add(tmp27, tmp28, tmp29); qqbar_sub_si(tmp27, tmp27, 630); qqbar_mul_si(tmp27, tmp27, 2); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_sub_si(tmp28, tmp28, 1); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_add(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 3); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_add(tmp25, tmp26, tmp27); qqbar_sub_si(tmp25, tmp25, 3); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_add(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 89); qqbar_sub_si(tmp23, tmp23, 126); qqbar_mul_si(tmp23, tmp23, 10); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 2); qqbar_sub_si(tmp25, tmp25, 3); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, -17); qqbar_add_si(tmp25, tmp25, 26); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 61); qqbar_sub_si(tmp25, tmp25, 85); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_mul_si(tmp22, tmp22, 2); qqbar_sqrt_ui(tmp23, 2); qqbar_neg(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sub(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 2); qqbar_sub_si(tmp26, tmp26, 3); qqbar_mul_si(tmp26, tmp26, 3); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, 61); qqbar_sub(tmp24, tmp25, tmp26); qqbar_add_si(tmp24, tmp24, 85); qqbar_sqrt_ui(tmp25, 2); qqbar_neg(tmp25, tmp25); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 5); qqbar_sub_si(tmp25, tmp25, 7); qqbar_mul_si(tmp25, tmp25, 11); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sub(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 445); qqbar_add(tmp21, tmp22, tmp23); qqbar_sub_si(tmp21, tmp21, 630); qqbar_mul_si(tmp21, tmp21, 4); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 1); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -12); qqbar_sqrt_ui(tmp22, 2); qqbar_neg(tmp22, tmp22); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_mul_si(tmp22, tmp22, 2); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul_si(tmp21, tmp21, 2); qqbar_sub(tmp19, tmp20, tmp21); qqbar_add_si(tmp19, tmp19, 24); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_add(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 3); qqbar_sub_si(tmp22, tmp22, 4); qqbar_mul_si(tmp22, tmp22, 3); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, -17); qqbar_add_si(tmp23, tmp23, 26); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 85); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 122); qqbar_sqrt_ui(tmp21, 2); qqbar_neg(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, 7); qqbar_sub_si(tmp21, tmp21, 10); qqbar_mul_si(tmp21, tmp21, 11); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, -17); qqbar_add_si(tmp22, tmp22, 26); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sub(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 630); qqbar_add(tmp17, tmp18, tmp19); qqbar_sub_si(tmp17, tmp17, 890); qqbar_mul_si(tmp17, tmp17, 8); qqbar_sqrt_ui(tmp18, 2); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_sub_si(tmp18, tmp18, 1); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_add(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp19, 2); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub_si(tmp19, tmp19, 1); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 3); qqbar_add(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_mul_si(tmp17, tmp17, 5); qqbar_sub(tmp15, tmp16, tmp17); qqbar_add_si(tmp15, tmp15, 8); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sub_si(tmp28, tmp28, 4); qqbar_mul_si(tmp28, tmp28, 3); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, -17); qqbar_add_si(tmp29, tmp29, 26); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 85); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 122); qqbar_sqrt_ui(tmp27, 2); qqbar_neg(tmp27, tmp27); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 7); qqbar_sub_si(tmp27, tmp27, 10); qqbar_mul_si(tmp27, tmp27, 11); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, -17); qqbar_add_si(tmp28, tmp28, 26); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sub(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 630); qqbar_add(tmp23, tmp24, tmp25); qqbar_sub_si(tmp23, tmp23, 890); qqbar_mul_si(tmp23, tmp23, 2); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_add(tmp24, tmp25, tmp26); qqbar_sub_si(tmp24, tmp24, 3); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_sub_si(tmp23, tmp23, 1); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 4896); qqbar_sub_si(tmp23, tmp23, 6923); qqbar_mul_si(tmp23, tmp23, 2); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sub(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 79); qqbar_sub_si(tmp25, tmp25, 112); qqbar_mul_si(tmp25, tmp25, 20); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 27); qqbar_sub_si(tmp28, tmp28, 38); qqbar_mul_si(tmp28, tmp28, 7); qqbar_sqrt_ui(tmp29, 2); qqbar_add_si(tmp29, tmp29, 2); qqbar_sqrt(tmp29, tmp29); qqbar_mul(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 342); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 484); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, -17); qqbar_add_si(tmp27, tmp27, 26); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 2820); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 3992); qqbar_sqrt_ui(tmp23, 2); qqbar_neg(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_add(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, 2); qqbar_sub_si(tmp32, tmp32, 3); qqbar_mul_si(tmp32, tmp32, 3); qqbar_sqrt_ui(tmp33, 2); qqbar_mul_si(tmp33, tmp33, -17); qqbar_add_si(tmp33, tmp33, 26); qqbar_sqrt(tmp33, tmp33); qqbar_mul(tmp31, tmp32, tmp33); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, 61); qqbar_sub(tmp30, tmp31, tmp32); qqbar_add_si(tmp30, tmp30, 85); qqbar_sqrt_ui(tmp31, 2); qqbar_neg(tmp31, tmp31); qqbar_add_si(tmp31, tmp31, 2); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, 5); qqbar_sub_si(tmp31, tmp31, 7); qqbar_mul_si(tmp31, tmp31, 11); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, -17); qqbar_add_si(tmp32, tmp32, 26); qqbar_sqrt(tmp32, tmp32); qqbar_mul(tmp30, tmp31, tmp32); qqbar_sub(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 445); qqbar_add(tmp27, tmp28, tmp29); qqbar_sub_si(tmp27, tmp27, 630); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 3); qqbar_sqrt_ui(tmp30, 2); qqbar_mul_si(tmp30, tmp30, -17); qqbar_add_si(tmp30, tmp30, 26); qqbar_sqrt(tmp30, tmp30); qqbar_add(tmp28, tmp29, tmp30); qqbar_sub_si(tmp28, tmp28, 3); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_sub_si(tmp27, tmp27, 1); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 89); qqbar_sub_si(tmp27, tmp27, 126); qqbar_mul_si(tmp27, tmp27, 10); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sub(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp29, 2); qqbar_mul_si(tmp29, tmp29, 61); qqbar_sub_si(tmp29, tmp29, 85); qqbar_sqrt_ui(tmp30, 2); qqbar_add_si(tmp30, tmp30, 2); qqbar_sqrt(tmp30, tmp30); qqbar_mul(tmp28, tmp29, tmp30); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, 2); qqbar_sub_si(tmp32, tmp32, 3); qqbar_sqrt_ui(tmp33, 2); qqbar_add_si(tmp33, tmp33, 2); qqbar_sqrt(tmp33, tmp33); qqbar_mul(tmp31, tmp32, tmp33); qqbar_sqrt_ui(tmp32, 2); qqbar_mul_si(tmp32, tmp32, 2); qqbar_sub(tmp30, tmp31, tmp32); qqbar_add_si(tmp30, tmp30, 3); qqbar_mul_si(tmp30, tmp30, 3); qqbar_sqrt_ui(tmp31, 2); qqbar_mul_si(tmp31, tmp31, -17); qqbar_add_si(tmp31, tmp31, 26); qqbar_sqrt(tmp31, tmp31); qqbar_mul(tmp29, tmp30, tmp31); qqbar_sub(tmp27, tmp28, tmp29); qqbar_sqrt_ui(tmp28, 2); qqbar_mul_si(tmp28, tmp28, 61); qqbar_sub(tmp26, tmp27, tmp28); qqbar_add_si(tmp26, tmp26, 85); qqbar_mul_si(tmp26, tmp26, 2); qqbar_sqrt_ui(tmp27, 2); qqbar_neg(tmp27, tmp27); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_mul(tmp25, tmp26, tmp27); qqbar_add(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 5); qqbar_sub_si(tmp27, tmp27, 7); qqbar_sqrt_ui(tmp28, 2); qqbar_add_si(tmp28, tmp28, 2); qqbar_sqrt(tmp28, tmp28); qqbar_mul(tmp26, tmp27, tmp28); qqbar_sqrt_ui(tmp27, 2); qqbar_mul_si(tmp27, tmp27, 5); qqbar_sub(tmp25, tmp26, tmp27); qqbar_add_si(tmp25, tmp25, 7); qqbar_mul_si(tmp25, tmp25, 22); qqbar_sqrt_ui(tmp26, 2); qqbar_mul_si(tmp26, tmp26, -17); qqbar_add_si(tmp26, tmp26, 26); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_add(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_mul_si(tmp23, tmp23, 890); qqbar_add(tmp21, tmp22, tmp23); qqbar_sub_si(tmp21, tmp21, 1260); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -12); qqbar_sqrt_ui(tmp25, 2); qqbar_neg(tmp25, tmp25); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_mul_si(tmp25, tmp25, 2); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, -17); qqbar_add_si(tmp24, tmp24, 26); qqbar_sqrt(tmp24, tmp24); qqbar_mul_si(tmp24, tmp24, 2); qqbar_sub(tmp22, tmp23, tmp24); qqbar_add_si(tmp22, tmp22, 24); qqbar_sqrt(tmp22, tmp22); qqbar_mul(tmp20, tmp21, tmp22); qqbar_add(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 319); qqbar_sub_si(tmp22, tmp22, 452); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul(tmp21, tmp22, tmp23); qqbar_sqrt_ui(tmp22, 2); qqbar_mul_si(tmp22, tmp22, 561); qqbar_sub(tmp20, tmp21, tmp22); qqbar_add_si(tmp20, tmp20, 794); qqbar_mul_si(tmp20, tmp20, 4); qqbar_sqrt_ui(tmp21, 2); qqbar_mul_si(tmp21, tmp21, -17); qqbar_add_si(tmp21, tmp21, 26); qqbar_sqrt(tmp21, tmp21); qqbar_mul(tmp19, tmp20, tmp21); qqbar_add(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 17064); qqbar_add(tmp16, tmp17, tmp18); qqbar_sub_si(tmp16, tmp16, 24132); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 1); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_sub_si(tmp20, tmp20, 1); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_add(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 1); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_add_si(tmp19, tmp19, 1); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_sub_si(tmp20, tmp20, 1); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_sub(tmp17, tmp18, tmp19); qqbar_sqrt_ui(tmp25, 2); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_add(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_add_si(tmp25, tmp25, 2); qqbar_sqrt(tmp25, tmp25); qqbar_sub_si(tmp25, tmp25, 1); qqbar_sqrt(tmp25, tmp25); qqbar_mul(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_mul_si(tmp24, tmp24, 3); qqbar_add(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_mul_si(tmp23, tmp23, 5); qqbar_sub(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 8); qqbar_sqrt_ui(tmp26, 2); qqbar_sqrt_ui(tmp27, 2); qqbar_add_si(tmp27, tmp27, 2); qqbar_sqrt(tmp27, tmp27); qqbar_add(tmp25, tmp26, tmp27); qqbar_sqrt_ui(tmp26, 2); qqbar_add_si(tmp26, tmp26, 2); qqbar_sqrt(tmp26, tmp26); qqbar_sub_si(tmp26, tmp26, 1); qqbar_sqrt(tmp26, tmp26); qqbar_mul(tmp24, tmp25, tmp26); qqbar_sqrt_ui(tmp25, 2); qqbar_mul_si(tmp25, tmp25, 3); qqbar_sub(tmp23, tmp24, tmp25); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_mul_si(tmp24, tmp24, 5); qqbar_add(tmp22, tmp23, tmp24); qqbar_sub_si(tmp22, tmp22, 8); qqbar_mul(tmp20, tmp21, tmp22); qqbar_sqrt_ui(tmp21, 2); qqbar_add_si(tmp21, tmp21, 2); qqbar_sqrt(tmp21, tmp21); qqbar_add_si(tmp21, tmp21, 2); qqbar_mul(tmp19, tmp20, tmp21); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_add_si(tmp23, tmp23, 1); qqbar_sqrt_ui(tmp24, 2); qqbar_add_si(tmp24, tmp24, 2); qqbar_sqrt(tmp24, tmp24); qqbar_sub_si(tmp24, tmp24, 1); qqbar_sqrt(tmp24, tmp24); qqbar_mul(tmp22, tmp23, tmp24); qqbar_sqrt_ui(tmp23, 2); qqbar_add_si(tmp23, tmp23, 2); qqbar_sqrt(tmp23, tmp23); qqbar_add(tmp21, tmp22, tmp23); qqbar_add_si(tmp21, tmp21, 1); qqbar_sqrt_ui(tmp22, 2); qqbar_add_si(tmp22, tmp22, 2); qqbar_sqrt(tmp22, tmp22); qqbar_sub_si(tmp22, tmp22, 2); qqbar_pow_ui(tmp22, tmp22, 3); qqbar_mul(tmp20, tmp21, tmp22); qqbar_div(tmp18, tmp19, tmp20); qqbar_sub(tmp16, tmp17, tmp18); qqbar_sub_si(tmp16, tmp16, 1); qqbar_mul(tmp14, tmp15, tmp16); qqbar_set_si(tmp18, 1); qqbar_div_si(tmp18, tmp18, 4); qqbar_neg(tmp18, tmp18); qqbar_sqrt_ui(tmp19, 2); qqbar_add_si(tmp19, tmp19, 2); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_set_si(tmp18, 1); qqbar_div_si(tmp18, tmp18, 2); qqbar_add(tmp16, tmp17, tmp18); qqbar_set_si(tmp17, 3); qqbar_div_si(tmp17, tmp17, 2); qqbar_pow(tmp15, tmp16, tmp17); qqbar_mul(tmp13, tmp14, tmp15); qqbar_div(tmp11, tmp12, tmp13); qqbar_add(tmp9, tmp10, tmp11); qqbar_mul(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp8, 2); qqbar_add_si(tmp8, tmp8, 2); qqbar_sqrt(tmp8, tmp8); qqbar_sub_si(tmp8, tmp8, 2); qqbar_div(tmp6, tmp7, tmp8); qqbar_sub(tmp4, tmp5, tmp6); qqbar_mul(tmp2, tmp3, tmp4); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 3); qqbar_sub_si(tmp15, tmp15, 4); qqbar_mul_si(tmp15, tmp15, 3); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, -17); qqbar_add_si(tmp16, tmp16, 26); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 85); qqbar_sub(tmp13, tmp14, tmp15); qqbar_add_si(tmp13, tmp13, 122); qqbar_sqrt_ui(tmp14, 2); qqbar_neg(tmp14, tmp14); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 7); qqbar_sub_si(tmp14, tmp14, 10); qqbar_mul_si(tmp14, tmp14, 11); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, -17); qqbar_add_si(tmp15, tmp15, 26); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sub(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, 630); qqbar_add(tmp10, tmp11, tmp12); qqbar_sub_si(tmp10, tmp10, 890); qqbar_mul_si(tmp10, tmp10, 2); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, 3); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, -17); qqbar_add_si(tmp13, tmp13, 26); qqbar_sqrt(tmp13, tmp13); qqbar_add(tmp11, tmp12, tmp13); qqbar_sub_si(tmp11, tmp11, 3); qqbar_sqrt(tmp11, tmp11); qqbar_mul(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_sub_si(tmp10, tmp10, 1); qqbar_sqrt(tmp10, tmp10); qqbar_mul(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 4896); qqbar_sub_si(tmp10, tmp10, 6923); qqbar_mul_si(tmp10, tmp10, 2); qqbar_sqrt_ui(tmp11, 2); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_mul(tmp9, tmp10, tmp11); qqbar_sub(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, 79); qqbar_sub_si(tmp12, tmp12, 112); qqbar_mul_si(tmp12, tmp12, 20); qqbar_sqrt_ui(tmp13, 2); qqbar_add_si(tmp13, tmp13, 2); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 27); qqbar_sub_si(tmp15, tmp15, 38); qqbar_mul_si(tmp15, tmp15, 7); qqbar_sqrt_ui(tmp16, 2); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 342); qqbar_sub(tmp13, tmp14, tmp15); qqbar_add_si(tmp13, tmp13, 484); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, -17); qqbar_add_si(tmp14, tmp14, 26); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sub(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, 2820); qqbar_sub(tmp9, tmp10, tmp11); qqbar_add_si(tmp9, tmp9, 3992); qqbar_sqrt_ui(tmp10, 2); qqbar_neg(tmp10, tmp10); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_mul(tmp8, tmp9, tmp10); qqbar_add(tmp6, tmp7, tmp8); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sub_si(tmp19, tmp19, 3); qqbar_mul_si(tmp19, tmp19, 3); qqbar_sqrt_ui(tmp20, 2); qqbar_mul_si(tmp20, tmp20, -17); qqbar_add_si(tmp20, tmp20, 26); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 61); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 85); qqbar_sqrt_ui(tmp18, 2); qqbar_neg(tmp18, tmp18); qqbar_add_si(tmp18, tmp18, 2); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, 5); qqbar_sub_si(tmp18, tmp18, 7); qqbar_mul_si(tmp18, tmp18, 11); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, -17); qqbar_add_si(tmp19, tmp19, 26); qqbar_sqrt(tmp19, tmp19); qqbar_mul(tmp17, tmp18, tmp19); qqbar_sub(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 445); qqbar_add(tmp14, tmp15, tmp16); qqbar_sub_si(tmp14, tmp14, 630); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 3); qqbar_sqrt_ui(tmp17, 2); qqbar_mul_si(tmp17, tmp17, -17); qqbar_add_si(tmp17, tmp17, 26); qqbar_sqrt(tmp17, tmp17); qqbar_add(tmp15, tmp16, tmp17); qqbar_sub_si(tmp15, tmp15, 3); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_sub_si(tmp14, tmp14, 1); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 89); qqbar_sub_si(tmp14, tmp14, 126); qqbar_mul_si(tmp14, tmp14, 10); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sub(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp16, 2); qqbar_mul_si(tmp16, tmp16, 61); qqbar_sub_si(tmp16, tmp16, 85); qqbar_sqrt_ui(tmp17, 2); qqbar_add_si(tmp17, tmp17, 2); qqbar_sqrt(tmp17, tmp17); qqbar_mul(tmp15, tmp16, tmp17); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sub_si(tmp19, tmp19, 3); qqbar_sqrt_ui(tmp20, 2); qqbar_add_si(tmp20, tmp20, 2); qqbar_sqrt(tmp20, tmp20); qqbar_mul(tmp18, tmp19, tmp20); qqbar_sqrt_ui(tmp19, 2); qqbar_mul_si(tmp19, tmp19, 2); qqbar_sub(tmp17, tmp18, tmp19); qqbar_add_si(tmp17, tmp17, 3); qqbar_mul_si(tmp17, tmp17, 3); qqbar_sqrt_ui(tmp18, 2); qqbar_mul_si(tmp18, tmp18, -17); qqbar_add_si(tmp18, tmp18, 26); qqbar_sqrt(tmp18, tmp18); qqbar_mul(tmp16, tmp17, tmp18); qqbar_sub(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, 61); qqbar_sub(tmp13, tmp14, tmp15); qqbar_add_si(tmp13, tmp13, 85); qqbar_mul_si(tmp13, tmp13, 2); qqbar_sqrt_ui(tmp14, 2); qqbar_neg(tmp14, tmp14); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_add(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 5); qqbar_sub_si(tmp14, tmp14, 7); qqbar_sqrt_ui(tmp15, 2); qqbar_add_si(tmp15, tmp15, 2); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_mul_si(tmp14, tmp14, 5); qqbar_sub(tmp12, tmp13, tmp14); qqbar_add_si(tmp12, tmp12, 7); qqbar_mul_si(tmp12, tmp12, 22); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, -17); qqbar_add_si(tmp13, tmp13, 26); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_add(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 890); qqbar_add(tmp8, tmp9, tmp10); qqbar_sub_si(tmp8, tmp8, 1260); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, -12); qqbar_sqrt_ui(tmp12, 2); qqbar_neg(tmp12, tmp12); qqbar_add_si(tmp12, tmp12, 2); qqbar_sqrt(tmp12, tmp12); qqbar_mul_si(tmp12, tmp12, 2); qqbar_sub(tmp10, tmp11, tmp12); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, -17); qqbar_add_si(tmp11, tmp11, 26); qqbar_sqrt(tmp11, tmp11); qqbar_mul_si(tmp11, tmp11, 2); qqbar_sub(tmp9, tmp10, tmp11); qqbar_add_si(tmp9, tmp9, 24); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_add(tmp5, tmp6, tmp7); qqbar_sqrt_ui(tmp9, 2); qqbar_mul_si(tmp9, tmp9, 319); qqbar_sub_si(tmp9, tmp9, 452); qqbar_sqrt_ui(tmp10, 2); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_mul(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp9, 2); qqbar_mul_si(tmp9, tmp9, 561); qqbar_sub(tmp7, tmp8, tmp9); qqbar_add_si(tmp7, tmp7, 794); qqbar_mul_si(tmp7, tmp7, 4); qqbar_sqrt_ui(tmp8, 2); qqbar_mul_si(tmp8, tmp8, -17); qqbar_add_si(tmp8, tmp8, 26); qqbar_sqrt(tmp8, tmp8); qqbar_mul(tmp6, tmp7, tmp8); qqbar_add(tmp4, tmp5, tmp6); qqbar_sqrt_ui(tmp5, 2); qqbar_mul_si(tmp5, tmp5, 17064); qqbar_add(tmp3, tmp4, tmp5); qqbar_sub_si(tmp3, tmp3, 24132); qqbar_div(tmp1, tmp2, tmp3); qqbar_sub(N, tmp0, tmp1); TIMEIT_ONCE_STOP flint_printf("Evaluating M...\n"); TIMEIT_ONCE_START qqbar_sqrt_ui(tmp6, 2); qqbar_mul_si(tmp6, tmp6, 6); qqbar_sqrt_ui(tmp7, 2); qqbar_neg(tmp7, tmp7); qqbar_add_si(tmp7, tmp7, 2); qqbar_sqrt(tmp7, tmp7); qqbar_add(tmp5, tmp6, tmp7); qqbar_sqrt_ui(tmp6, 2); qqbar_mul_si(tmp6, tmp6, -17); qqbar_add_si(tmp6, tmp6, 26); qqbar_sqrt(tmp6, tmp6); qqbar_add(tmp4, tmp5, tmp6); qqbar_sub_si(tmp4, tmp4, 8); qqbar_mul_si(tmp4, tmp4, 4); qqbar_sqrt_ui(tmp6, 2); qqbar_mul_si(tmp6, tmp6, 3); qqbar_sqrt_ui(tmp7, 2); qqbar_neg(tmp7, tmp7); qqbar_add_si(tmp7, tmp7, 2); qqbar_sqrt(tmp7, tmp7); qqbar_add(tmp5, tmp6, tmp7); qqbar_sub_si(tmp5, tmp5, 5); qqbar_sqrt(tmp5, tmp5); qqbar_mul(tmp3, tmp4, tmp5); qqbar_sqrt_ui(tmp6, 2); qqbar_mul_si(tmp6, tmp6, 3); qqbar_sqrt_ui(tmp7, 2); qqbar_mul_si(tmp7, tmp7, -17); qqbar_add_si(tmp7, tmp7, 26); qqbar_sqrt(tmp7, tmp7); qqbar_add(tmp5, tmp6, tmp7); qqbar_sub_si(tmp5, tmp5, 3); qqbar_sqrt(tmp5, tmp5); qqbar_i(tmp10); qqbar_mul_si(tmp10, tmp10, -24); qqbar_sqrt_ui(tmp11, 2); qqbar_mul(tmp9, tmp10, tmp11); qqbar_i(tmp11); qqbar_mul_si(tmp11, tmp11, 4); qqbar_sqrt_ui(tmp12, 2); qqbar_neg(tmp12, tmp12); qqbar_add_si(tmp12, tmp12, 2); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_sub(tmp8, tmp9, tmp10); qqbar_i(tmp10); qqbar_mul_si(tmp10, tmp10, 4); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, -17); qqbar_add_si(tmp11, tmp11, 26); qqbar_sqrt(tmp11, tmp11); qqbar_mul(tmp9, tmp10, tmp11); qqbar_sub(tmp7, tmp8, tmp9); qqbar_i(tmp8); qqbar_mul_si(tmp8, tmp8, 32); qqbar_add(tmp6, tmp7, tmp8); qqbar_mul(tmp4, tmp5, tmp6); qqbar_sub(tmp2, tmp3, tmp4); qqbar_sqrt_ui(tmp9, 2); qqbar_sqrt_ui(tmp10, 2); qqbar_neg(tmp10, tmp10); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_mul(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp10, 2); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, -17); qqbar_add_si(tmp11, tmp11, 26); qqbar_sqrt(tmp11, tmp11); qqbar_mul(tmp9, tmp10, tmp11); qqbar_add(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp8, 2); qqbar_mul_si(tmp8, tmp8, 8); qqbar_sub(tmp6, tmp7, tmp8); qqbar_add_si(tmp6, tmp6, 12); qqbar_sqrt_ui(tmp8, 2); qqbar_mul_si(tmp8, tmp8, 3); qqbar_sqrt_ui(tmp9, 2); qqbar_neg(tmp9, tmp9); qqbar_add_si(tmp9, tmp9, 2); qqbar_sqrt(tmp9, tmp9); qqbar_add(tmp7, tmp8, tmp9); qqbar_sub_si(tmp7, tmp7, 5); qqbar_sqrt(tmp7, tmp7); qqbar_mul(tmp5, tmp6, tmp7); qqbar_i(tmp12); qqbar_sqrt_ui(tmp13, 2); qqbar_mul(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp12, 2); qqbar_neg(tmp12, tmp12); qqbar_add_si(tmp12, tmp12, 2); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_i(tmp13); qqbar_sqrt_ui(tmp14, 2); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, -17); qqbar_add_si(tmp13, tmp13, 26); qqbar_sqrt(tmp13, tmp13); qqbar_mul(tmp11, tmp12, tmp13); qqbar_add(tmp9, tmp10, tmp11); qqbar_i(tmp11); qqbar_mul_si(tmp11, tmp11, 8); qqbar_sqrt_ui(tmp12, 2); qqbar_mul(tmp10, tmp11, tmp12); qqbar_sub(tmp8, tmp9, tmp10); qqbar_i(tmp9); qqbar_mul_si(tmp9, tmp9, 12); qqbar_add(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp9, 2); qqbar_mul_si(tmp9, tmp9, 3); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, -17); qqbar_add_si(tmp10, tmp10, 26); qqbar_sqrt(tmp10, tmp10); qqbar_add(tmp8, tmp9, tmp10); qqbar_sub_si(tmp8, tmp8, 3); qqbar_sqrt(tmp8, tmp8); qqbar_mul(tmp6, tmp7, tmp8); qqbar_add(tmp4, tmp5, tmp6); qqbar_sqrt_ui(tmp7, 2); qqbar_mul_si(tmp7, tmp7, -12); qqbar_sqrt_ui(tmp8, 2); qqbar_neg(tmp8, tmp8); qqbar_add_si(tmp8, tmp8, 2); qqbar_sqrt(tmp8, tmp8); qqbar_mul_si(tmp8, tmp8, 2); qqbar_sub(tmp6, tmp7, tmp8); qqbar_sqrt_ui(tmp7, 2); qqbar_mul_si(tmp7, tmp7, -17); qqbar_add_si(tmp7, tmp7, 26); qqbar_sqrt(tmp7, tmp7); qqbar_mul_si(tmp7, tmp7, 2); qqbar_sub(tmp5, tmp6, tmp7); qqbar_add_si(tmp5, tmp5, 24); qqbar_sqrt(tmp5, tmp5); qqbar_mul(tmp3, tmp4, tmp5); qqbar_sub(tmp1, tmp2, tmp3); qqbar_i(tmp10); qqbar_mul_si(tmp10, tmp10, 24); qqbar_sqrt_ui(tmp11, 2); qqbar_mul(tmp9, tmp10, tmp11); qqbar_i(tmp11); qqbar_mul_si(tmp11, tmp11, 4); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, -17); qqbar_add_si(tmp12, tmp12, 26); qqbar_sqrt(tmp12, tmp12); qqbar_mul(tmp10, tmp11, tmp12); qqbar_add(tmp8, tmp9, tmp10); qqbar_i(tmp9); qqbar_mul_si(tmp9, tmp9, 32); qqbar_sub(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp8, 2); qqbar_neg(tmp8, tmp8); qqbar_add_si(tmp8, tmp8, 2); qqbar_sqrt(tmp8, tmp8); qqbar_mul(tmp6, tmp7, tmp8); qqbar_i(tmp9); qqbar_mul_si(tmp9, tmp9, 8); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 3); qqbar_sub_si(tmp10, tmp10, 4); qqbar_mul(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp9, 2); qqbar_mul_si(tmp9, tmp9, -17); qqbar_add_si(tmp9, tmp9, 26); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_add(tmp5, tmp6, tmp7); qqbar_i(tmp7); qqbar_mul_si(tmp7, tmp7, 228); qqbar_sqrt_ui(tmp8, 2); qqbar_mul(tmp6, tmp7, tmp8); qqbar_sub(tmp4, tmp5, tmp6); qqbar_i(tmp5); qqbar_mul_si(tmp5, tmp5, 328); qqbar_add(tmp3, tmp4, tmp5); qqbar_sqrt_ui(tmp4, 2); qqbar_add_si(tmp4, tmp4, 2); qqbar_sqrt(tmp4, tmp4); qqbar_sub_si(tmp4, tmp4, 1); qqbar_sqrt(tmp4, tmp4); qqbar_mul(tmp2, tmp3, tmp4); qqbar_sub(tmp0, tmp1, tmp2); qqbar_neg(tmp0, tmp0); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 6); qqbar_sqrt_ui(tmp11, 2); qqbar_neg(tmp11, tmp11); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_add(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, -17); qqbar_add_si(tmp10, tmp10, 26); qqbar_sqrt(tmp10, tmp10); qqbar_add(tmp8, tmp9, tmp10); qqbar_sub_si(tmp8, tmp8, 8); qqbar_mul_si(tmp8, tmp8, 4); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 3); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, -17); qqbar_add_si(tmp11, tmp11, 26); qqbar_sqrt(tmp11, tmp11); qqbar_add(tmp9, tmp10, tmp11); qqbar_sub_si(tmp9, tmp9, 3); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp8, 2); qqbar_add_si(tmp8, tmp8, 2); qqbar_sqrt(tmp8, tmp8); qqbar_sub_si(tmp8, tmp8, 1); qqbar_sqrt(tmp8, tmp8); qqbar_mul(tmp6, tmp7, tmp8); qqbar_sqrt_ui(tmp10, 2); qqbar_mul_si(tmp10, tmp10, 3); qqbar_sqrt_ui(tmp11, 2); qqbar_neg(tmp11, tmp11); qqbar_add_si(tmp11, tmp11, 2); qqbar_sqrt(tmp11, tmp11); qqbar_add(tmp9, tmp10, tmp11); qqbar_sub_si(tmp9, tmp9, 5); qqbar_sqrt(tmp9, tmp9); qqbar_i(tmp14); qqbar_mul_si(tmp14, tmp14, -24); qqbar_sqrt_ui(tmp15, 2); qqbar_mul(tmp13, tmp14, tmp15); qqbar_i(tmp15); qqbar_mul_si(tmp15, tmp15, 4); qqbar_sqrt_ui(tmp16, 2); qqbar_neg(tmp16, tmp16); qqbar_add_si(tmp16, tmp16, 2); qqbar_sqrt(tmp16, tmp16); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sub(tmp12, tmp13, tmp14); qqbar_i(tmp14); qqbar_mul_si(tmp14, tmp14, 4); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, -17); qqbar_add_si(tmp15, tmp15, 26); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sub(tmp11, tmp12, tmp13); qqbar_i(tmp12); qqbar_mul_si(tmp12, tmp12, 32); qqbar_add(tmp10, tmp11, tmp12); qqbar_mul(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp9, 2); qqbar_add_si(tmp9, tmp9, 2); qqbar_sqrt(tmp9, tmp9); qqbar_sub_si(tmp9, tmp9, 1); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_add(tmp5, tmp6, tmp7); qqbar_sqrt_ui(tmp8, 2); qqbar_mul_si(tmp8, tmp8, 6); qqbar_sqrt_ui(tmp9, 2); qqbar_mul_si(tmp9, tmp9, -17); qqbar_add_si(tmp9, tmp9, 26); qqbar_sqrt(tmp9, tmp9); qqbar_add(tmp7, tmp8, tmp9); qqbar_sub_si(tmp7, tmp7, 8); qqbar_mul_si(tmp7, tmp7, 4); qqbar_sqrt_ui(tmp8, 2); qqbar_neg(tmp8, tmp8); qqbar_add_si(tmp8, tmp8, 2); qqbar_sqrt(tmp8, tmp8); qqbar_mul(tmp6, tmp7, tmp8); qqbar_sub(tmp4, tmp5, tmp6); qqbar_i(tmp14); qqbar_sqrt_ui(tmp15, 2); qqbar_mul(tmp13, tmp14, tmp15); qqbar_sqrt_ui(tmp14, 2); qqbar_neg(tmp14, tmp14); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_i(tmp15); qqbar_sqrt_ui(tmp16, 2); qqbar_mul(tmp14, tmp15, tmp16); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, -17); qqbar_add_si(tmp15, tmp15, 26); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_add(tmp11, tmp12, tmp13); qqbar_i(tmp13); qqbar_mul_si(tmp13, tmp13, 8); qqbar_sqrt_ui(tmp14, 2); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sub(tmp10, tmp11, tmp12); qqbar_i(tmp11); qqbar_mul_si(tmp11, tmp11, 12); qqbar_add(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp11, 2); qqbar_mul_si(tmp11, tmp11, 3); qqbar_sqrt_ui(tmp12, 2); qqbar_neg(tmp12, tmp12); qqbar_add_si(tmp12, tmp12, 2); qqbar_sqrt(tmp12, tmp12); qqbar_add(tmp10, tmp11, tmp12); qqbar_sub_si(tmp10, tmp10, 5); qqbar_sqrt(tmp10, tmp10); qqbar_mul(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp9, 2); qqbar_add_si(tmp9, tmp9, 2); qqbar_sqrt(tmp9, tmp9); qqbar_sub_si(tmp9, tmp9, 1); qqbar_sqrt(tmp9, tmp9); qqbar_mul(tmp7, tmp8, tmp9); qqbar_sqrt_ui(tmp13, 2); qqbar_sqrt_ui(tmp14, 2); qqbar_neg(tmp14, tmp14); qqbar_add_si(tmp14, tmp14, 2); qqbar_sqrt(tmp14, tmp14); qqbar_mul(tmp12, tmp13, tmp14); qqbar_sqrt_ui(tmp14, 2); qqbar_sqrt_ui(tmp15, 2); qqbar_mul_si(tmp15, tmp15, -17); qqbar_add_si(tmp15, tmp15, 26); qqbar_sqrt(tmp15, tmp15); qqbar_mul(tmp13, tmp14, tmp15); qqbar_add(tmp11, tmp12, tmp13); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, 8); qqbar_sub(tmp10, tmp11, tmp12); qqbar_add_si(tmp10, tmp10, 12); qqbar_sqrt_ui(tmp12, 2); qqbar_mul_si(tmp12, tmp12, 3); qqbar_sqrt_ui(tmp13, 2); qqbar_mul_si(tmp13, tmp13, -17); qqbar_add_si(tmp13, tmp13, 26); qqbar_sqrt(tmp13, tmp13); qqbar_add(tmp11, tmp12, tmp13); qqbar_sub_si(tmp11, tmp11, 3); qqbar_sqrt(tmp11, tmp11); qqbar_mul(tmp9, tmp10, tmp11); qqbar_sqrt_ui(tmp10, 2); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_sub_si(tmp10, tmp10, 1); qqbar_sqrt(tmp10, tmp10); qqbar_mul(tmp8, tmp9, tmp10); qqbar_sub(tmp6, tmp7, tmp8); qqbar_sqrt_ui(tmp9, 2); qqbar_mul_si(tmp9, tmp9, -12); qqbar_sqrt_ui(tmp10, 2); qqbar_neg(tmp10, tmp10); qqbar_add_si(tmp10, tmp10, 2); qqbar_sqrt(tmp10, tmp10); qqbar_mul_si(tmp10, tmp10, 2); qqbar_sub(tmp8, tmp9, tmp10); qqbar_sqrt_ui(tmp9, 2); qqbar_mul_si(tmp9, tmp9, -17); qqbar_add_si(tmp9, tmp9, 26); qqbar_sqrt(tmp9, tmp9); qqbar_mul_si(tmp9, tmp9, 2); qqbar_sub(tmp7, tmp8, tmp9); qqbar_add_si(tmp7, tmp7, 24); qqbar_sqrt(tmp7, tmp7); qqbar_mul(tmp5, tmp6, tmp7); qqbar_add(tmp3, tmp4, tmp5); qqbar_sqrt_ui(tmp5, 2); qqbar_mul_si(tmp5, tmp5, 3); qqbar_sub_si(tmp5, tmp5, 4); qqbar_mul_si(tmp5, tmp5, 8); qqbar_sqrt_ui(tmp6, 2); qqbar_mul_si(tmp6, tmp6, -17); qqbar_add_si(tmp6, tmp6, 26); qqbar_sqrt(tmp6, tmp6); qqbar_mul(tmp4, tmp5, tmp6); qqbar_sub(tmp2, tmp3, tmp4); qqbar_sqrt_ui(tmp3, 2); qqbar_mul_si(tmp3, tmp3, 228); qqbar_add(tmp1, tmp2, tmp3); qqbar_sub_si(tmp1, tmp1, 328); qqbar_div(M, tmp0, tmp1); TIMEIT_ONCE_STOP flint_printf("Evaluating E = -(1-|M|^2)^2...\n"); TIMEIT_ONCE_START qqbar_abs(E, M); qqbar_pow_ui(E, E, 2); qqbar_si_sub(E, 1, E); qqbar_pow_ui(E, E, 2); qqbar_neg(E, E); TIMEIT_ONCE_STOP flint_printf("N ~ "); qqbar_printn(N, 50); flint_printf("\n"); flint_printf("E ~ "); qqbar_printn(E, 50); flint_printf("\n"); flint_printf("Testing E = N...\n"); TIMEIT_ONCE_START equal = qqbar_equal(E, N) ? T_TRUE : T_FALSE; TIMEIT_ONCE_STOP flint_printf("\nEqual = "); truth_print(equal); flint_printf("\n"); qqbar_clear(tmp0); qqbar_clear(tmp1); qqbar_clear(tmp2); qqbar_clear(tmp3); qqbar_clear(tmp4); qqbar_clear(tmp5); qqbar_clear(tmp6); qqbar_clear(tmp7); qqbar_clear(tmp8); qqbar_clear(tmp9); qqbar_clear(tmp10); qqbar_clear(tmp11); qqbar_clear(tmp12); qqbar_clear(tmp13); qqbar_clear(tmp14); qqbar_clear(tmp15); qqbar_clear(tmp16); qqbar_clear(tmp17); qqbar_clear(tmp18); qqbar_clear(tmp19); qqbar_clear(tmp20); qqbar_clear(tmp21); qqbar_clear(tmp22); qqbar_clear(tmp23); qqbar_clear(tmp24); qqbar_clear(tmp25); qqbar_clear(tmp26); qqbar_clear(tmp27); qqbar_clear(tmp28); qqbar_clear(tmp29); qqbar_clear(tmp30); qqbar_clear(tmp31); qqbar_clear(tmp32); qqbar_clear(tmp33); qqbar_clear(tmp34); qqbar_clear(N); qqbar_clear(M); qqbar_clear(E); } int main(int argc, char *argv[]) { TIMEIT_ONCE_START if (argc >= 2 && strcmp(argv[1], "-ca") == 0) main_ca(); else main_qqbar(); flint_printf("\n"); flint_printf("Total: "); TIMEIT_ONCE_STOP SHOW_MEMORY_USAGE flint_cleanup(); return EXIT_SUCCESS; } calcium-0.4.1/examples/machin.c000066400000000000000000000071331407704557200163710ustar00rootroot00000000000000/* This file is public domain. Author: Fredrik Johansson. */ #include "flint/profiler.h" #include "ca.h" void simple_ca_atan_p_q(ca_t res, ulong p, ulong q, ca_ctx_t ctx) { ca_set_ui(res, p, ctx); ca_div_ui(res, res, q, ctx); ca_atan(res, res, ctx); } /* valid for -1 < x < 1 */ void simple_ca_atanh(ca_t res, const ca_t x, ca_ctx_t ctx) { ca_t t, u; ca_init(t, ctx); ca_init(u, ctx); ca_add_ui(t, x, 1, ctx); ca_sub_ui(u, x, 1, ctx); ca_neg(u, u, ctx); ca_div(res, t, u, ctx); ca_log(res, res, ctx); ca_div_ui(res, res, 2, ctx); ca_clear(t, ctx); ca_clear(u, ctx); } void simple_ca_atanh_p_q(ca_t res, ulong p, ulong q, ca_ctx_t ctx) { ca_set_ui(res, p, ctx); ca_div_ui(res, res, q, ctx); simple_ca_atanh(res, res, ctx); } #define NUM_FORMULAS 8 slong machin_formulas[NUM_FORMULAS][4][2] = { {{1, 1}, {0, 0}, {0, 0}, {0, 0}}, {{1, 2}, {1, 3}, {0, 0}, {0, 0}}, {{2, 2}, {-1, 7}, {0, 0}, {0, 0}}, {{2, 3}, {1, 7}, {0, 0}, {0, 0}}, {{4, 5}, {-1, 239}, {0, 0}, {0, 0}}, {{1, 2}, {1, 5}, {1, 8}, {0, 0}}, {{1, 3}, {1, 4}, {1, 7}, {1, 13}}, {{12, 49}, {32, 57}, {-5, 239}, {12, 110443}}, }; #define NUM_FORMULAS2 7 slong hyperbolic_logs[NUM_FORMULAS2] = {2, 3, 5, 2, 3, 5, 7}; slong hyperbolic_machin_formulas[NUM_FORMULAS2][4][2] = { {{14, 31}, {10, 49}, {6, 161}, {0, 0}}, {{22, 31}, {16, 49}, {10, 161}, {0, 0}}, {{32, 31}, {24, 49}, {14, 161}, {0, 0}}, {{144, 251}, {54, 449}, {-38, 4801}, {62, 8749}}, {{228, 251}, {86, 449}, {-60, 4801}, {98, 8749}}, {{334, 251}, {126, 449}, {-88, 4801}, {144, 8749}}, {{404, 251}, {152, 449}, {-106, 4801}, {174, 8749}}, }; int main(int argc, char *argv[]) { ca_ctx_t ctx; ca_t x, y, pi4; slong i, j, c, q; TIMEIT_ONCE_START ca_ctx_init(ctx); ca_init(x, ctx); ca_init(y, ctx); ca_init(pi4, ctx); ca_pi(pi4, ctx); ca_div_ui(pi4, pi4, 4, ctx); for (i = 0; i < NUM_FORMULAS; i++) { flint_printf("["); ca_zero(x, ctx); for (j = 0; j < 4; j++) { c = machin_formulas[i][j][0]; q = machin_formulas[i][j][1]; if (c != 0) { if (j != 0) flint_printf(" + "); flint_printf("(%wd)*atan(1/%wd)", c, q); simple_ca_atan_p_q(y, 1, q, ctx); ca_mul_si(y, y, c, ctx); ca_add(x, x, y, ctx); } } flint_printf(" - pi/4] = "); ca_sub(x, x, pi4, ctx); ca_print(x, ctx); flint_printf("\n"); } flint_printf("\n"); for (i = 0; i < NUM_FORMULAS2; i++) { flint_printf("["); ca_zero(x, ctx); for (j = 0; j < 4; j++) { c = hyperbolic_machin_formulas[i][j][0]; q = hyperbolic_machin_formulas[i][j][1]; if (c != 0) { if (j != 0) flint_printf(" + "); flint_printf("(%wd)*atanh(1/%wd)", c, q); simple_ca_atanh_p_q(y, 1, q, ctx); ca_mul_si(y, y, c, ctx); ca_add(x, x, y, ctx); } } flint_printf(" - log(%wd)] = ", hyperbolic_logs[i]); ca_set_ui(y, hyperbolic_logs[i], ctx); ca_log(y, y, ctx); ca_sub(x, x, y, ctx); ca_print(x, ctx); flint_printf("\n"); } ca_clear(x, ctx); ca_clear(y, ctx); ca_clear(pi4, ctx); ca_ctx_clear(ctx); flint_printf("\n"); TIMEIT_ONCE_STOP SHOW_MEMORY_USAGE flint_cleanup(); return EXIT_SUCCESS; } calcium-0.4.1/examples/swinnerton_dyer_poly.c000066400000000000000000000055441407704557200214320ustar00rootroot00000000000000/* This file is public domain. Author: Fredrik Johansson. */ #include "flint/profiler.h" #include "ca.h" #include "ca_vec.h" void _ca_poly_mullow(ca_ptr res, ca_srcptr x, slong xlen, ca_srcptr y, slong ylen, slong len, ca_ctx_t ctx) { slong i, j; ca_t t; for (i = 0; i < len; i++) ca_zero(res + i, ctx); ca_init(t, ctx); for (i = 0; i < xlen; i++) { for (j = 0; j < FLINT_MIN(ylen, len - i); j++) { ca_mul(t, x + i, y + j, ctx); ca_add(res + i + j, res + i + j, t, ctx); } } ca_clear(t, ctx); } void swinnerton_dyer_poly(ca_ptr T, ulong n, slong trunc, ca_ctx_t ctx) { ca_ptr square_roots, tmp1, tmp2, tmp3; ca_t one; slong i, j, k, N; N = WORD(1) << n; trunc = FLINT_MIN(trunc, N + 1); ca_init(one, ctx); ca_one(one, ctx); square_roots = _ca_vec_init(n, ctx); tmp1 = flint_malloc((N/2 + 1) * sizeof(ca_struct)); tmp2 = flint_malloc((N/2 + 1) * sizeof(ca_struct)); tmp3 = _ca_vec_init(N, ctx); for (i = 0; i < n; i++) ca_sqrt_ui(square_roots + i, n_nth_prime(i + 1), ctx); /* Build linear factors */ for (i = 0; i < N; i++) { ca_zero(T + i, ctx); for (j = 0; j < n; j++) { if ((i >> j) & 1) ca_add(T + i, T + i, square_roots + j, ctx); else ca_sub(T + i, T + i, square_roots + j, ctx); } } /* For each level... */ for (i = 0; i < n; i++) { slong stride = UWORD(1) << i; for (j = 0; j < N; j += 2*stride) { for (k = 0; k < stride; k++) { tmp1[k] = T[j + k]; tmp2[k] = T[j + stride + k]; } tmp1[stride] = *one; tmp2[stride] = *one; _ca_poly_mullow(tmp3, tmp1, stride + 1, tmp2, stride + 1, FLINT_MIN(2 * stride, trunc), ctx); _ca_vec_set(T + j, tmp3, FLINT_MIN(2 * stride, trunc), ctx); } } ca_one(T + N, ctx); _ca_vec_clear(square_roots, n, ctx); flint_free(tmp1); flint_free(tmp2); _ca_vec_clear(tmp3, UWORD(1) << n, ctx); ca_clear(one, ctx); } int main(int argc, char *argv[]) { ca_ctx_t ctx; ca_ptr poly; slong i, n, N; if (argc < 2) { flint_printf("usage: build/examples/sdpoly n\n"); return 1; } n = atol(argv[1]); if (n < 0 || n > 20) flint_abort(); N = (1 << n); TIMEIT_ONCE_START ca_ctx_init(ctx); poly = _ca_vec_init(N + 1, ctx); swinnerton_dyer_poly(poly, n, N + 1, ctx); for (i = 0; i <= N; i++) { ca_print(poly + i, ctx); flint_printf("\n"); } _ca_vec_clear(poly, N + 1, ctx); ca_ctx_clear(ctx); flint_printf("\n"); TIMEIT_ONCE_STOP SHOW_MEMORY_USAGE flint_cleanup(); return EXIT_SUCCESS; } calcium-0.4.1/fexpr.h000066400000000000000000000375761407704557200144630ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef FEXPR_H #define FEXPR_H #ifdef FEXPR_INLINES_C #define FEXPR_INLINE #else #define FEXPR_INLINE static __inline__ #endif #ifdef __cplusplus extern "C" { #endif #include #include "flint/flint.h" #include "flint/fmpz.h" #include "flint/fmpq.h" #include "calcium.h" #include "fmpz_mpoly_q.h" #define FEXPR_TYPE_SMALL_INT UWORD(0) #define FEXPR_TYPE_SMALL_SYMBOL UWORD(1) #define FEXPR_TYPE_SMALL_STRING UWORD(2) #define FEXPR_TYPE_BIG_INT_POS UWORD(3) #define FEXPR_TYPE_BIG_INT_NEG UWORD(4) #define FEXPR_TYPE_BIG_SYMBOL UWORD(5) #define FEXPR_TYPE_BIG_STRING UWORD(6) #define FEXPR_TYPE_CALL0 UWORD(7) #define FEXPR_TYPE_CALL1 UWORD(8) #define FEXPR_TYPE_CALL2 UWORD(9) #define FEXPR_TYPE_CALL3 UWORD(10) #define FEXPR_TYPE_CALL4 UWORD(11) #define FEXPR_TYPE_CALLN UWORD(12) #define FEXPR_TYPE_BITS 4 #define FEXPR_TYPE_MASK ((UWORD(1) << FEXPR_TYPE_BITS) - 1) #define FEXPR_COEFF_MAX ((WORD(1) << (FLINT_BITS - FEXPR_TYPE_BITS - 1)) - 1) #define FEXPR_COEFF_MIN (-FEXPR_COEFF_MAX) #define FEXPR_TYPE(head) ((head) & FEXPR_TYPE_MASK) #define FEXPR_SIZE(head) ((slong) ((FEXPR_TYPE(head) <= FEXPR_TYPE_SMALL_STRING) ? 1 : (head) >> FEXPR_TYPE_BITS)) #define FEXPR_HEADER_SIZE WORD(1) #define FEXPR_SMALL_SYMBOL_LEN ((FLINT_BITS / 8) - 1) #define FEXPR_BUILTIN_ID(head) ((head) >> 16) typedef struct { ulong * data; slong alloc; } fexpr_struct; typedef fexpr_struct fexpr_t[1]; typedef fexpr_struct * fexpr_ptr; typedef const fexpr_struct * fexpr_srcptr; typedef struct { fexpr_struct * entries; slong length; slong alloc; } fexpr_vec_struct; typedef fexpr_vec_struct fexpr_vec_t[1]; #define fexpr_vec_entry(vec, i) ((vec)->entries + (i)) FEXPR_INLINE void fexpr_init(fexpr_t expr) { expr->data = flint_malloc(sizeof(ulong)); expr->data[0] = 0; expr->alloc = 1; } FEXPR_INLINE void fexpr_clear(fexpr_t expr) { flint_free(expr->data); } FEXPR_INLINE fexpr_ptr _fexpr_vec_init(slong len) { slong i; fexpr_ptr vec = flint_malloc(sizeof(fexpr_struct) * len); for (i = 0; i < len; i++) fexpr_init(vec + i); return vec; } FEXPR_INLINE void _fexpr_vec_clear(fexpr_ptr vec, slong len) { slong i; for (i = 0; i < len; i++) fexpr_clear(vec + i); flint_free(vec); } FEXPR_INLINE void fexpr_fit_size(fexpr_t expr, slong size) { if (expr->alloc < size) { size = FLINT_MAX(size, 2 * expr->alloc); expr->data = flint_realloc(expr->data, size * sizeof(ulong)); expr->alloc = size; } } FEXPR_INLINE slong _fexpr_size(const ulong * expr) { ulong head = expr[0]; return FEXPR_SIZE(head); } FEXPR_INLINE slong fexpr_size(const fexpr_t expr) { return _fexpr_size(expr->data); } FEXPR_INLINE void fexpr_set(fexpr_t res, const fexpr_t expr) { if (res != expr) { slong size = fexpr_size(expr); fexpr_fit_size(res, size); flint_mpn_copyi(res->data, expr->data, size); } } FEXPR_INLINE void fexpr_swap(fexpr_t a, fexpr_t b) { fexpr_struct tmp = *a; *a = *b; *b = tmp; } FEXPR_INLINE int _mpn_equal(mp_srcptr a, mp_srcptr b, slong len) { slong i; for (i = 0; i < len; i++) if (a[i] != b[i]) return 0; return 1; } FEXPR_INLINE int fexpr_equal(const fexpr_t a, const fexpr_t b) { ulong ha, hb; slong sa, sb; ha = a->data[0]; hb = b->data[0]; if (ha != hb) return 0; sa = FEXPR_SIZE(ha); sb = FEXPR_SIZE(hb); if (sa != sb) return 0; return _mpn_equal(a->data + 1, b->data + 1, sa - 1); } /* todo: document, test */ int fexpr_equal_si(const fexpr_t expr, slong c); int fexpr_equal_ui(const fexpr_t expr, ulong c); ulong fexpr_hash(const fexpr_t expr); int fexpr_cmp_fast(const fexpr_t a, const fexpr_t b); FEXPR_INLINE void _fexpr_vec_sort_fast(fexpr_ptr vec, slong len) { qsort(vec, len, sizeof(fexpr_struct), (int(*)(const void*,const void*)) fexpr_cmp_fast); } FEXPR_INLINE int _fexpr_is_integer(const ulong * expr) { ulong type = FEXPR_TYPE(expr[0]); return (type == FEXPR_TYPE_SMALL_INT) || (type == FEXPR_TYPE_BIG_INT_POS) || (type == FEXPR_TYPE_BIG_INT_NEG); } FEXPR_INLINE int fexpr_is_integer(const fexpr_t expr) { return _fexpr_is_integer(expr->data); } /* todo: document, test */ int fexpr_is_neg_integer(const fexpr_t expr); FEXPR_INLINE int _fexpr_is_symbol(const ulong * expr) { ulong type = FEXPR_TYPE(expr[0]); return (type == FEXPR_TYPE_SMALL_SYMBOL) || (type == FEXPR_TYPE_BIG_SYMBOL); } FEXPR_INLINE int fexpr_is_symbol(const fexpr_t expr) { return _fexpr_is_symbol(expr->data); } FEXPR_INLINE int _fexpr_is_string(const ulong * expr) { ulong type = FEXPR_TYPE(expr[0]); return (type == FEXPR_TYPE_SMALL_STRING) || (type == FEXPR_TYPE_BIG_STRING); } FEXPR_INLINE int fexpr_is_string(const fexpr_t expr) { return _fexpr_is_string(expr->data); } FEXPR_INLINE int _fexpr_is_atom(const ulong * expr) { return FEXPR_TYPE(expr[0]) <= FEXPR_TYPE_BIG_STRING; } FEXPR_INLINE int fexpr_is_atom(const fexpr_t expr) { return _fexpr_is_atom(expr->data); } FEXPR_INLINE void fexpr_zero(fexpr_t res) { res->data[0] = 0; } FEXPR_INLINE int fexpr_is_zero(const fexpr_t expr) { return expr->data[0] == 0; } void fexpr_set_si(fexpr_t res, slong c); void fexpr_set_ui(fexpr_t res, ulong c); void fexpr_set_fmpz(fexpr_t res, const fmpz_t c); int fexpr_get_fmpz(fmpz_t c, const fexpr_t x); void fexpr_set_fmpq(fexpr_t res, const fmpq_t x); FEXPR_INLINE void fexpr_set_symbol_builtin(fexpr_t res, slong id) { res->data[0] = FEXPR_TYPE_SMALL_SYMBOL | (id << 16); } void fexpr_set_symbol_str(fexpr_t res, const char * s); char * fexpr_get_symbol_str(const fexpr_t expr); void fexpr_set_string(fexpr_t res, const char * s); char * fexpr_get_string(const fexpr_t expr); slong fexpr_depth(const fexpr_t expr); slong fexpr_num_leaves(const fexpr_t expr); FEXPR_INLINE slong fexpr_size_bytes(const fexpr_t expr) { return fexpr_size(expr) * sizeof(ulong); } FEXPR_INLINE slong fexpr_allocated_bytes(const fexpr_t expr) { return expr->alloc * sizeof(ulong); } /* todo: document */ FEXPR_INLINE int fexpr_is_any_builtin_symbol(const fexpr_t expr) { ulong head; head = expr->data[0]; return (FEXPR_TYPE(head) == FEXPR_TYPE_SMALL_SYMBOL) && (((head >> 8) & 0xff) == 0); } /* todo: document */ FEXPR_INLINE int fexpr_is_builtin_symbol(const fexpr_t expr, slong i) { ulong head; head = expr->data[0]; return (FEXPR_TYPE(head) == FEXPR_TYPE_SMALL_SYMBOL) && (((head >> 8) & 0xff) == 0) && (FEXPR_BUILTIN_ID(head) == i); } /* todo: document, test */ int fexpr_is_builtin_call(const fexpr_t expr, slong i); int fexpr_is_any_builtin_call(const fexpr_t expr); FEXPR_INLINE slong fexpr_nargs(const fexpr_t expr) { ulong type = FEXPR_TYPE(expr->data[0]); if (FEXPR_TYPE_CALL0 <= type && type <= FEXPR_TYPE_CALL4) { return type - FEXPR_TYPE_CALL0; } else if (type == FEXPR_TYPE_CALLN) { return expr->data[1]; } else { return -1; } } void fexpr_func(fexpr_t res, const fexpr_t expr); void fexpr_view_func(fexpr_t res, const fexpr_t expr); void fexpr_arg(fexpr_t res, const fexpr_t expr, slong i); void fexpr_view_arg(fexpr_t res, const fexpr_t expr, slong i); FEXPR_INLINE void fexpr_view_next(fexpr_t view) { view->data += fexpr_size(view); } /* todo: handle aliasing! */ void fexpr_call0(fexpr_t res, const fexpr_t f); void fexpr_call1(fexpr_t res, const fexpr_t f, const fexpr_t x1); void fexpr_call2(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2); void fexpr_call3(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2, const fexpr_t x3); void fexpr_call4(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2, const fexpr_t x3, const fexpr_t x4); void fexpr_call_vec(fexpr_t res, const fexpr_t f, fexpr_srcptr args, slong len); void fexpr_call_builtin1(fexpr_t res, slong f, const fexpr_t x); void fexpr_call_builtin2(fexpr_t res, slong f, const fexpr_t x, const fexpr_t y); /* Subexpressions and replacement */ int fexpr_contains(const fexpr_t expr, const fexpr_t x); int fexpr_replace(fexpr_t res, const fexpr_t expr, const fexpr_t x, const fexpr_t y); int fexpr_replace2(fexpr_t res, const fexpr_t expr, const fexpr_t x1, const fexpr_t y1, const fexpr_t x2, const fexpr_t y2); int fexpr_replace_vec(fexpr_t res, const fexpr_t expr, const fexpr_vec_t xs, const fexpr_vec_t ys); /* Input/output */ void fexpr_write(calcium_stream_t stream, const fexpr_t expr); void fexpr_print(const fexpr_t expr); char * fexpr_get_str(const fexpr_t expr); /* LaTeX output */ #define FEXPR_LATEX_SMALL 1 #define FEXPR_LATEX_LOGIC 2 void fexpr_write_latex(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_print_latex(const fexpr_t expr, ulong flags); char * fexpr_get_str_latex(const fexpr_t expr, ulong flags); void fexpr_write_latex_call(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_subscript(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_subscript_call(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_infix(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_mul(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_div(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_neg_pos(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_add(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_sub(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_pow(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_exp(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_factorial(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_integral(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_sum_product(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_divsum(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_limit(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_derivative(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_logic(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_collection(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_matrix(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_simple(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_simple2(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_simple2_small(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_alg_structure(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_setop(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_cases(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_where(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_show_form(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_range(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_decimal(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_call1_optional_derivative(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_call2_optional_derivative(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_sub1_call1_optional_derivative(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_sub1_call2_optional_derivative(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_misc_special(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_write_latex_residue(calcium_stream_t out, const fexpr_t expr, ulong flags); void fexpr_set_arf(fexpr_t res, const arf_t x); void fexpr_set_d(fexpr_t res, double x); void fexpr_set_re_im_d(fexpr_t res, double x, double y); void fexpr_neg(fexpr_t res, const fexpr_t a); void fexpr_add(fexpr_t res, const fexpr_t a, const fexpr_t b); void fexpr_sub(fexpr_t res, const fexpr_t a, const fexpr_t b); void fexpr_mul(fexpr_t res, const fexpr_t a, const fexpr_t b); void fexpr_div(fexpr_t res, const fexpr_t a, const fexpr_t b); void fexpr_pow(fexpr_t res, const fexpr_t a, const fexpr_t b); int fexpr_is_arithmetic_operation(const fexpr_t expr); void fexpr_arithmetic_nodes(fexpr_vec_t nodes, const fexpr_t expr); int fexpr_get_fmpz_mpoly_q(fmpz_mpoly_q_t res, const fexpr_t expr, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx); void fexpr_set_fmpz_mpoly(fexpr_t res, const fmpz_mpoly_t poly, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx); void fexpr_set_fmpz_mpoly_q(fexpr_t res, const fmpz_mpoly_q_t frac, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx); int fexpr_expanded_normal_form(fexpr_t res, const fexpr_t expr, ulong flags); /* Vectors */ FEXPR_INLINE void fexpr_vec_init(fexpr_vec_t vec, slong len) { if (len == 0) { vec->entries = NULL; vec->length = 0; vec->alloc = 0; } else { slong i; vec->entries = flint_malloc(sizeof(fexpr_struct) * len); for (i = 0; i < len; i++) fexpr_init(vec->entries + i); vec->length = vec->alloc = len; } } FEXPR_INLINE void fexpr_vec_print(const fexpr_vec_t F) { slong i; flint_printf("["); for (i = 0; i < F->length; i++) { fexpr_print(F->entries + i); if (i < F->length - 1) flint_printf(", "); } flint_printf("]"); } FEXPR_INLINE void fexpr_vec_swap(fexpr_vec_t x, fexpr_vec_t y) { fexpr_vec_t tmp; *tmp = *x; *x = *y; *y = *tmp; } FEXPR_INLINE void fexpr_vec_fit_length(fexpr_vec_t vec, slong len) { if (len > vec->alloc) { slong i; if (len < 2 * vec->alloc) len = 2 * vec->alloc; vec->entries = flint_realloc(vec->entries, len * sizeof(fexpr_struct)); for (i = vec->alloc; i < len; i++) fexpr_init(vec->entries + i); vec->alloc = len; } } FEXPR_INLINE void fexpr_vec_clear(fexpr_vec_t vec) { slong i; for (i = 0; i < vec->alloc; i++) fexpr_clear(vec->entries + i); flint_free(vec->entries); } FEXPR_INLINE void fexpr_vec_set(fexpr_vec_t dest, const fexpr_vec_t src) { if (dest != src) { slong i; fexpr_vec_fit_length(dest, src->length); for (i = 0; i < src->length; i++) fexpr_set(dest->entries + i, src->entries + i); dest->length = src->length; } } FEXPR_INLINE void fexpr_vec_append(fexpr_vec_t vec, const fexpr_t f) { fexpr_vec_fit_length(vec, vec->length + 1); fexpr_set(vec->entries + vec->length, f); vec->length++; } FEXPR_INLINE slong fexpr_vec_insert_unique(fexpr_vec_t vec, const fexpr_t f) { slong i; for (i = 0; i < vec->length; i++) { if (fexpr_equal(vec->entries + i, f)) return i; } fexpr_vec_append(vec, f); return vec->length - 1; } FEXPR_INLINE void fexpr_vec_set_length(fexpr_vec_t vec, slong len) { slong i; if (len > vec->length) { fexpr_vec_fit_length(vec, len); for (i = vec->length; i < len; i++) fexpr_zero(vec->entries + i); } else if (len < vec->length) { for (i = len; i < vec->length; i++) fexpr_zero(vec->entries + i); } vec->length = len; } #ifdef __cplusplus } #endif #endif calcium-0.4.1/fexpr/000077500000000000000000000000001407704557200142705ustar00rootroot00000000000000calcium-0.4.1/fexpr/arg.c000066400000000000000000000042641407704557200152130ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" /* todo: bounds checking? */ void fexpr_arg(fexpr_t res, const fexpr_t expr, slong i) { const ulong * data; slong j, size; ulong type = FEXPR_TYPE(expr->data[0]); if (FEXPR_TYPE_CALL0 <= type && type <= FEXPR_TYPE_CALL4) { data = expr->data + FEXPR_HEADER_SIZE; data += FEXPR_SIZE(data[0]); /* skip f */ for (j = 0; j < i; j++) data += FEXPR_SIZE(data[0]); /* jump ahead */ size = FEXPR_SIZE(data[0]); fexpr_fit_size(res, size); flint_mpn_copyi(res->data, data, size); } else if (type == FEXPR_TYPE_CALLN) { data = expr->data + expr->data[3 + i / 4]; for (j = 0; j < i % 4; j++) data += FEXPR_SIZE(data[0]); size = FEXPR_SIZE(data[0]); fexpr_fit_size(res, size); flint_mpn_copyi(res->data, data, size); } else { flint_printf("fexpr_arg: a non-atomic expression is required\n"); flint_abort(); } } void fexpr_view_arg(fexpr_t res, const fexpr_t expr, slong i) { const ulong * data; slong j; ulong type = FEXPR_TYPE(expr->data[0]); if (FEXPR_TYPE_CALL0 <= type && type <= FEXPR_TYPE_CALL4) { data = expr->data + FEXPR_HEADER_SIZE; data += FEXPR_SIZE(data[0]); /* skip f */ for (j = 0; j < i; j++) data += FEXPR_SIZE(data[0]); /* jump ahead */ res->data = (ulong *) data; res->alloc = 0; } else if (type == FEXPR_TYPE_CALLN) { data = expr->data + expr->data[3 + i / 4]; for (j = 0; j < i % 4; j++) data += FEXPR_SIZE(data[0]); res->data = (ulong *) data; res->alloc = 0; } else { flint_printf("fexpr_view_arg: a non-atomic expression is required\n"); flint_abort(); } } calcium-0.4.1/fexpr/arithmetic.c000066400000000000000000000021121407704557200165610ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" void fexpr_neg(fexpr_t res, const fexpr_t a) { fexpr_call_builtin1(res, FEXPR_Neg, a); } void fexpr_add(fexpr_t res, const fexpr_t a, const fexpr_t b) { fexpr_call_builtin2(res, FEXPR_Add, a, b); } void fexpr_sub(fexpr_t res, const fexpr_t a, const fexpr_t b) { fexpr_call_builtin2(res, FEXPR_Sub, a, b); } void fexpr_mul(fexpr_t res, const fexpr_t a, const fexpr_t b) { fexpr_call_builtin2(res, FEXPR_Mul, a, b); } void fexpr_div(fexpr_t res, const fexpr_t a, const fexpr_t b) { fexpr_call_builtin2(res, FEXPR_Div, a, b); } void fexpr_pow(fexpr_t res, const fexpr_t a, const fexpr_t b) { fexpr_call_builtin2(res, FEXPR_Pow, a, b); } calcium-0.4.1/fexpr/arithmetic_nodes.c000066400000000000000000000025001407704557200177520ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" static void traverse(fexpr_vec_t nodes, const fexpr_t expr) { slong i, nargs; fexpr_t view; if (fexpr_is_integer(expr)) return; if (fexpr_is_arithmetic_operation(expr)) { nargs = fexpr_nargs(expr); fexpr_view_arg(view, expr, 0); for (i = 0; i < nargs; i++) { traverse(nodes, view); fexpr_view_next(view); } return; } if (fexpr_is_builtin_call(expr, FEXPR_Pow) && (fexpr_nargs(expr) == 2)) { fexpr_t base, exp; fexpr_view_arg(base, expr, 0); fexpr_view_arg(exp, expr, 1); if (fexpr_is_integer(exp)) { traverse(nodes, base); return; } } fexpr_vec_insert_unique(nodes, expr); } void fexpr_arithmetic_nodes(fexpr_vec_t nodes, const fexpr_t expr) { fexpr_vec_set_length(nodes, 0); traverse(nodes, expr); } calcium-0.4.1/fexpr/call0.c000066400000000000000000000014011407704557200154230ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" void fexpr_call0(fexpr_t res, const fexpr_t f) { slong res_size, f_size; mp_ptr out; f_size = fexpr_size(f); res_size = FEXPR_HEADER_SIZE + f_size; fexpr_fit_size(res, res_size); out = res->data; out[0] = FEXPR_TYPE_CALL0 | (res_size << FEXPR_TYPE_BITS); out += FEXPR_HEADER_SIZE; flint_mpn_copyi(out, f->data, f_size); } calcium-0.4.1/fexpr/call1.c000066400000000000000000000023711407704557200154330ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" void fexpr_call1(fexpr_t res, const fexpr_t f, const fexpr_t x1) { slong res_size, f_size, x1_size; mp_ptr out; f_size = fexpr_size(f); x1_size = fexpr_size(x1); res_size = FEXPR_HEADER_SIZE + f_size + x1_size; fexpr_fit_size(res, res_size); out = res->data; out[0] = FEXPR_TYPE_CALL1 | (res_size << FEXPR_TYPE_BITS); out += FEXPR_HEADER_SIZE; flint_mpn_copyi(out, f->data, f_size); out += f_size; flint_mpn_copyi(out, x1->data, x1_size); } void fexpr_call_builtin1(fexpr_t res, slong f, const fexpr_t x) { fexpr_t t; ulong d; t->data = &d; t->alloc = 1; fexpr_set_symbol_builtin(t, f); if (res == x) { fexpr_t u; fexpr_init(u); fexpr_call1(u, t, x); fexpr_swap(res, u); fexpr_clear(u); } else { fexpr_call1(res, t, x); } } calcium-0.4.1/fexpr/call2.c000066400000000000000000000026341407704557200154360ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" void fexpr_call2(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2) { slong res_size, f_size, x1_size, x2_size; mp_ptr out; f_size = fexpr_size(f); x1_size = fexpr_size(x1); x2_size = fexpr_size(x2); res_size = FEXPR_HEADER_SIZE + f_size + x1_size + x2_size; fexpr_fit_size(res, res_size); out = res->data; out[0] = FEXPR_TYPE_CALL2 | (res_size << FEXPR_TYPE_BITS); out += FEXPR_HEADER_SIZE; flint_mpn_copyi(out, f->data, f_size); out += f_size; flint_mpn_copyi(out, x1->data, x1_size); out += x1_size; flint_mpn_copyi(out, x2->data, x2_size); } void fexpr_call_builtin2(fexpr_t res, slong f, const fexpr_t x, const fexpr_t y) { fexpr_t t; ulong d; t->data = &d; t->alloc = 1; fexpr_set_symbol_builtin(t, f); if (res == x || res == y) { fexpr_t u; fexpr_init(u); fexpr_call2(u, t, x, y); fexpr_swap(res, u); fexpr_clear(u); } else { fexpr_call2(res, t, x, y); } } calcium-0.4.1/fexpr/call3.c000066400000000000000000000022001407704557200154240ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" void fexpr_call3(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2, const fexpr_t x3) { slong res_size, f_size, x1_size, x2_size, x3_size; mp_ptr out; f_size = fexpr_size(f); x1_size = fexpr_size(x1); x2_size = fexpr_size(x2); x3_size = fexpr_size(x3); res_size = FEXPR_HEADER_SIZE + f_size + x1_size + x2_size + x3_size; fexpr_fit_size(res, res_size); out = res->data; out[0] = FEXPR_TYPE_CALL3 | (res_size << FEXPR_TYPE_BITS); out += FEXPR_HEADER_SIZE; flint_mpn_copyi(out, f->data, f_size); out += f_size; flint_mpn_copyi(out, x1->data, x1_size); out += x1_size; flint_mpn_copyi(out, x2->data, x2_size); out += x2_size; flint_mpn_copyi(out, x3->data, x3_size); } calcium-0.4.1/fexpr/call4.c000066400000000000000000000024001407704557200154270ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" void fexpr_call4(fexpr_t res, const fexpr_t f, const fexpr_t x1, const fexpr_t x2, const fexpr_t x3, const fexpr_t x4) { slong res_size, f_size, x1_size, x2_size, x3_size, x4_size; mp_ptr out; f_size = fexpr_size(f); x1_size = fexpr_size(x1); x2_size = fexpr_size(x2); x3_size = fexpr_size(x3); x4_size = fexpr_size(x4); res_size = FEXPR_HEADER_SIZE + f_size + x1_size + x2_size + x3_size + x4_size; fexpr_fit_size(res, res_size); out = res->data; out[0] = FEXPR_TYPE_CALL4 | (res_size << FEXPR_TYPE_BITS); out += FEXPR_HEADER_SIZE; flint_mpn_copyi(out, f->data, f_size); out += f_size; flint_mpn_copyi(out, x1->data, x1_size); out += x1_size; flint_mpn_copyi(out, x2->data, x2_size); out += x2_size; flint_mpn_copyi(out, x3->data, x3_size); out += x3_size; flint_mpn_copyi(out, x4->data, x4_size); } calcium-0.4.1/fexpr/call_vec.c000066400000000000000000000036311407704557200162070ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" void fexpr_call_vec(fexpr_t res, const fexpr_t f, fexpr_srcptr args, slong len) { if (len == 0) { fexpr_call0(res, f); } else if (len == 1) { fexpr_call1(res, f, args); } else if (len == 2) { fexpr_call2(res, f, args, args + 1); } else if (len == 3) { fexpr_call3(res, f, args, args + 1, args + 2); } else if (len == 4) { fexpr_call4(res, f, args, args + 1, args + 2, args + 3); } else { slong i, f_size, args_size, index_size, size, pos, arg_size; mp_ptr out; f_size = fexpr_size(f); args_size = 0; for (i = 0; i < len; i++) args_size += fexpr_size(args + i); /* write index: data[1] = nargs data[2] = position of f data[3], data[4], ..., positions of every 1/4 args for random access */ index_size = 2 + (len + 4 - 1) / 4; size = 1 + index_size + f_size + args_size; fexpr_fit_size(res, size); out = res->data; out[0] = FEXPR_TYPE_CALLN | (size << FEXPR_TYPE_BITS); out[1] = len; pos = 1 + index_size; out[2] = pos; flint_mpn_copyi(out + pos, f->data, f_size); pos += f_size; for (i = 0; i < len; i++) { if (i % 4 == 0) out[3 + i / 4] = pos; arg_size = fexpr_size(args + i); flint_mpn_copyi(out + pos, args[i].data, arg_size); pos += arg_size; } } } calcium-0.4.1/fexpr/cmp_fast.c000066400000000000000000000015441407704557200162340ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" int fexpr_cmp_fast(const fexpr_t a, const fexpr_t b) { ulong ha, hb; slong sa, sb; slong i; ha = a->data[0]; hb = b->data[0]; if (ha != hb) return (ha > hb) ? 1 : -1; sa = FEXPR_SIZE(ha); sb = FEXPR_SIZE(hb); if (sa != sb) return 0; for (i = 1; i < sa; i++) { ha = a->data[i]; hb = b->data[i]; if (ha != hb) return (ha > hb) ? 1 : -1; } return 0; } calcium-0.4.1/fexpr/contains.c000066400000000000000000000021561407704557200162560ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" int fexpr_contains(const fexpr_t expr, const fexpr_t x) { fexpr_t func, arg; slong expr_size, x_size, i, nargs; expr_size = fexpr_size(expr); x_size = fexpr_size(x); if (expr_size < x_size) return 0; if (expr_size == x_size) return _mpn_equal(expr->data, x->data, x_size); nargs = fexpr_nargs(expr); if (nargs < 0) return 0; fexpr_view_func(func, expr); if (fexpr_contains(func, x)) return 1; if (nargs <= 0) return 0; fexpr_view_arg(arg, expr, 0); for (i = 0; i < nargs; i++) { if (fexpr_contains(arg, x)) return 1; if (i < nargs - 1) fexpr_view_next(arg); } return 0; } calcium-0.4.1/fexpr/depth.c000066400000000000000000000016231407704557200155420ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" slong fexpr_depth(const fexpr_t expr) { if (fexpr_is_atom(expr)) { return 1; } else { fexpr_t func, arg; slong i, depth, d, nargs; fexpr_view_func(func, expr); depth = fexpr_depth(func); nargs = fexpr_nargs(expr); *arg = *func; for (i = 0; i < nargs; i++) { fexpr_view_next(arg); d = fexpr_depth(arg); depth = FLINT_MAX(depth, d); } return depth + 1; } } calcium-0.4.1/fexpr/equal_si.c000066400000000000000000000014701407704557200162400ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" int fexpr_equal_si(const fexpr_t expr, slong c) { if (c >= FEXPR_COEFF_MIN && c <= FEXPR_COEFF_MAX) return expr->data[0] == (c << FEXPR_TYPE_BITS); else if (c > 0) return (expr->data[0] == (FEXPR_TYPE_BIG_INT_POS | (2 << FEXPR_TYPE_BITS)) && expr->data[1] == c); else return (expr->data[0] == (FEXPR_TYPE_BIG_INT_NEG | (2 << FEXPR_TYPE_BITS)) && expr->data[1] == (-(ulong) c)); } calcium-0.4.1/fexpr/equal_ui.c000066400000000000000000000012521407704557200162400ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" int fexpr_equal_ui(const fexpr_t expr, ulong c) { if (c <= FEXPR_COEFF_MAX) return expr->data[0] == (c << FEXPR_TYPE_BITS); else return (expr->data[0] == (FEXPR_TYPE_BIG_INT_POS | (2 << FEXPR_TYPE_BITS)) && expr->data[1] == c); } calcium-0.4.1/fexpr/expanded_normal_form.c000066400000000000000000000022051407704557200206160ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" int fexpr_expanded_normal_form(fexpr_t res, const fexpr_t expr, ulong flags) { fexpr_vec_t args; fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t frac; int success; fexpr_vec_init(args, 0); fexpr_arithmetic_nodes(args, expr); _fexpr_vec_sort_fast(args->entries, args->length); /* todo: when length == 0, use fmpq arithmetic instead */ fmpz_mpoly_ctx_init(ctx, FLINT_MAX(args->length, 1), ORD_LEX); fmpz_mpoly_q_init(frac, ctx); success = fexpr_get_fmpz_mpoly_q(frac, expr, args, ctx); if (success) fexpr_set_fmpz_mpoly_q(res, frac, args, ctx); else fexpr_set(res, expr); fmpz_mpoly_q_clear(frac, ctx); fmpz_mpoly_ctx_clear(ctx); fexpr_vec_clear(args); return success; } calcium-0.4.1/fexpr/func.c000066400000000000000000000027441407704557200153760ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" void fexpr_func(fexpr_t res, const fexpr_t expr) { ulong type = FEXPR_TYPE(expr->data[0]); slong size; const ulong * data; if (FEXPR_TYPE_CALL0 <= type && type <= FEXPR_TYPE_CALL4) { data = expr->data + FEXPR_HEADER_SIZE; } else if (type == FEXPR_TYPE_CALLN) { data = expr->data + expr->data[2]; } else { flint_printf("fexpr_func: a non-atomic expression is required\n"); flint_abort(); } size = FEXPR_SIZE(data[0]); fexpr_fit_size(res, size); flint_mpn_copyi(res->data, data, size); } void fexpr_view_func(fexpr_t res, const fexpr_t expr) { ulong type = FEXPR_TYPE(expr->data[0]); const ulong * data; if (FEXPR_TYPE_CALL0 <= type && type <= FEXPR_TYPE_CALL4) { data = expr->data + FEXPR_HEADER_SIZE; } else if (type == FEXPR_TYPE_CALLN) { data = expr->data + expr->data[2]; } else { flint_printf("fexpr_view_func: a non-atomic expression is required\n"); flint_abort(); } res->data = (ulong *) data; res->alloc = 0; } calcium-0.4.1/fexpr/get_fmpz.c000066400000000000000000000023711407704557200162520ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" int fexpr_get_fmpz(fmpz_t c, const fexpr_t x) { ulong head = x->data[0]; if (FEXPR_TYPE(head) == FEXPR_TYPE_SMALL_INT) { _fmpz_demote(c); *c = ((slong) head) >> FEXPR_TYPE_BITS; } else { slong nlimbs; int negative; nlimbs = FEXPR_SIZE(head) - 1; if (FEXPR_TYPE(head) == FEXPR_TYPE_BIG_INT_POS) { negative = 0; } else if (FEXPR_TYPE(head) == FEXPR_TYPE_BIG_INT_NEG) { negative = 1; } else { return 0; } if (nlimbs == 1 && x->data[1] <= COEFF_MAX) { _fmpz_demote(c); *c = negative ? (-(slong) x->data[1]) : x->data[1]; } else { fmpz_set_mpn_large(c, x->data + 1, nlimbs, negative); } } return 1; } calcium-0.4.1/fexpr/get_fmpz_mpoly_q.c000066400000000000000000000100671407704557200200130ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" int fexpr_get_fmpz_mpoly_q(fmpz_mpoly_q_t res, const fexpr_t expr, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx) { if (fexpr_is_integer(expr)) { fmpz_t c; fmpz_init(c); fexpr_get_fmpz(c, expr); fmpz_mpoly_q_set_fmpz(res, c, ctx); fmpz_clear(c); return 1; } else { slong i, nargs; ulong op_head; fexpr_t func, arg; int success; if (fexpr_is_arithmetic_operation(expr)) { fmpz_mpoly_q_t A, B; nargs = fexpr_nargs(expr); if (nargs == 0) { /* not implemented */ return 0; } success = 1; fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fexpr_view_func(func, expr); op_head = func->data[0]; fexpr_view_arg(arg, expr, 0); success = fexpr_get_fmpz_mpoly_q(res, arg, vars, ctx); if (!success) goto cleanup1; /* todo: verify nargs == 1 */ if (op_head == FEXPR_SYMBOL_Neg) { fmpz_mpoly_q_neg(res, res, ctx); goto cleanup1; } for (i = 1; i < nargs; i++) { fexpr_view_next(arg); success = fexpr_get_fmpz_mpoly_q(A, arg, vars, ctx); if (!success) goto cleanup1; if (op_head == FEXPR_SYMBOL_Add) fmpz_mpoly_q_add(B, res, A, ctx); else if (op_head == FEXPR_SYMBOL_Sub) fmpz_mpoly_q_sub(B, res, A, ctx); else if (op_head == FEXPR_SYMBOL_Mul) fmpz_mpoly_q_mul(B, res, A, ctx); else if (op_head == FEXPR_SYMBOL_Div) { /* formal division by zero */ if (fmpz_mpoly_q_is_zero(A, ctx)) success = 0; else fmpz_mpoly_q_div(B, res, A, ctx); } fmpz_mpoly_q_swap(res, B, ctx); } cleanup1: fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); return success; } if (fexpr_is_builtin_call(expr, FEXPR_Pow) && (fexpr_nargs(expr) == 2)) { fexpr_t base, exp; int success; fexpr_view_arg(base, expr, 0); fexpr_view_arg(exp, expr, 1); if (fexpr_is_integer(exp)) { fmpz_t c; success = fexpr_get_fmpz_mpoly_q(res, base, vars, ctx); if (!success) return 0; fmpz_init(c); fexpr_get_fmpz(c, exp); if (fmpz_sgn(c) < 0) { if (fmpz_mpoly_q_is_zero(res, ctx)) { success = 0; goto cleanup2; } fmpz_neg(c, c); fmpz_mpoly_q_inv(res, res, ctx); } success = (fmpz_mpoly_pow_fmpz(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_numref(res), c, ctx) && fmpz_mpoly_pow_fmpz(fmpz_mpoly_q_denref(res), fmpz_mpoly_q_denref(res), c, ctx)); cleanup2: fmpz_clear(c); return success; } } for (i = 0; i < vars->length; i++) { if (fexpr_equal(expr, fexpr_vec_entry(vars, i))) { fmpz_mpoly_q_gen(res, i, ctx); return 1; } } return 0; } } calcium-0.4.1/fexpr/get_string.c000066400000000000000000000023301407704557200165770ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" char * fexpr_get_string(const fexpr_t expr) { char * res; slong i, len; ulong head = expr->data[0]; if (FEXPR_TYPE(head) == FEXPR_TYPE_SMALL_STRING) { res = flint_malloc(FEXPR_SMALL_SYMBOL_LEN + 1); res[FEXPR_SMALL_SYMBOL_LEN] = '\0'; for (i = 0; i < FEXPR_SMALL_SYMBOL_LEN; i++) { res[i] = (head >> ((i + 1) * 8)); if (res[i] == '\0') break; } } else if (FEXPR_TYPE(head) == FEXPR_TYPE_BIG_STRING) { len = strlen((const char *) (expr->data + 1)); res = flint_malloc(len + 1); memcpy(res, (const char *) (expr->data + 1), len + 1); } else { flint_printf("fexpr_get_string: a string is required\n"); flint_abort(); } return res; } calcium-0.4.1/fexpr/get_symbol_str.c000066400000000000000000000027631407704557200175000ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" char * fexpr_get_symbol_str(const fexpr_t expr) { char * res; slong i, len; ulong head = expr->data[0]; if (FEXPR_TYPE(head) == FEXPR_TYPE_SMALL_SYMBOL) { if (((head >> 8) & 0xff) == 0) { i = head >> 16; len = strlen(fexpr_builtin_table[i].string); res = flint_malloc(len + 1); memcpy(res, fexpr_builtin_table[i].string, len + 1); return res; } res = flint_malloc(FEXPR_SMALL_SYMBOL_LEN + 1); res[FEXPR_SMALL_SYMBOL_LEN] = '\0'; for (i = 0; i < FEXPR_SMALL_SYMBOL_LEN; i++) { res[i] = (head >> ((i + 1) * 8)); if (res[i] == '\0') break; } } else if (FEXPR_TYPE(head) == FEXPR_TYPE_BIG_SYMBOL) { len = strlen((const char *) (expr->data + 1)); res = flint_malloc(len + 1); memcpy(res, (const char *) (expr->data + 1), len + 1); } else { flint_printf("fexpr_get_symbol_str: a symbol is required\n"); flint_abort(); } return res; } calcium-0.4.1/fexpr/hash.c000066400000000000000000000012121407704557200153530ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" ulong fexpr_hash(const fexpr_t expr) { ulong head, hash; slong i, size; hash = head = expr->data[0]; size = FEXPR_SIZE(head); for (i = 1; i < size; i++) hash = expr->data[i] * 1000003 + hash; return hash; } calcium-0.4.1/fexpr/inlines.c000066400000000000000000000006601407704557200160770ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #define FEXPR_INLINES_C #include "fexpr.h" calcium-0.4.1/fexpr/is_any_builtin_call.c000066400000000000000000000011411407704557200204340ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" int fexpr_is_any_builtin_call(const fexpr_t expr) { fexpr_t func; if (fexpr_is_atom(expr)) return 0; fexpr_view_func(func, expr); return fexpr_is_any_builtin_symbol(func); } calcium-0.4.1/fexpr/is_arithmetic_operation.c000066400000000000000000000022521407704557200213410ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" #define FEXPR_IS_ARITHMETIC_OP(h) \ ((h) == FEXPR_SYMBOL_Add || (h) == FEXPR_SYMBOL_Sub || \ (h) == FEXPR_SYMBOL_Mul || (h) == FEXPR_SYMBOL_Div || \ (h) == FEXPR_SYMBOL_Neg || (h) == FEXPR_SYMBOL_Pos) int fexpr_is_arithmetic_operation(const fexpr_t expr) { ulong head; fexpr_t func; head = expr->data[0]; switch (FEXPR_TYPE(head)) { case FEXPR_TYPE_CALL0: case FEXPR_TYPE_CALL1: case FEXPR_TYPE_CALL2: case FEXPR_TYPE_CALL3: case FEXPR_TYPE_CALL4: return FEXPR_IS_ARITHMETIC_OP(expr->data[1]); case FEXPR_TYPE_CALLN: fexpr_view_func(func, expr); return FEXPR_IS_ARITHMETIC_OP(func->data[0]); default: return 0; } } calcium-0.4.1/fexpr/is_builtin_call.c000066400000000000000000000011451407704557200175710ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" int fexpr_is_builtin_call(const fexpr_t expr, slong i) { fexpr_t func; if (fexpr_is_atom(expr)) return 0; fexpr_view_func(func, expr); return fexpr_is_builtin_symbol(func, i); } calcium-0.4.1/fexpr/is_neg_integer.c000066400000000000000000000012521407704557200174150ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" int fexpr_is_neg_integer(const fexpr_t expr) { ulong head = expr->data[0]; if (FEXPR_TYPE(head) == FEXPR_TYPE_SMALL_INT) return (((slong) head) >> FEXPR_TYPE_BITS) < 0; if (FEXPR_TYPE(head) == FEXPR_TYPE_BIG_INT_NEG) return 1; return 0; } calcium-0.4.1/fexpr/num_leaves.c000066400000000000000000000015731407704557200166000ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" slong fexpr_num_leaves(const fexpr_t expr) { if (fexpr_is_atom(expr)) { return 1; } else { fexpr_t func, arg; slong i, leaves, nargs; fexpr_view_func(func, expr); leaves = fexpr_num_leaves(func); nargs = fexpr_nargs(expr); *arg = *func; for (i = 0; i < nargs; i++) { fexpr_view_next(arg); leaves += fexpr_num_leaves(arg); } return leaves; } } calcium-0.4.1/fexpr/numerical_enclosure.c000066400000000000000000000334721407704557200205030ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "acb_hypgeom.h" #include "acb_modular.h" #include "acb_dirichlet.h" #include "fexpr.h" #include "fexpr_builtin.h" void _acb_root(acb_t res, const acb_t x, const acb_t y, slong prec) { if (acb_is_int(y) && arf_sgn(arb_midref(acb_realref(y))) > 0 && arf_cmpabs_ui(arb_midref(acb_realref(y)), 1000) <= 0) { acb_root_ui(res, x, arf_get_si(arb_midref(acb_realref(y)), ARF_RND_DOWN), prec); } else { acb_t e; acb_init(e); acb_inv(e, y, prec); acb_pow(res, x, e, prec); acb_clear(e); } } #define REQUIRE_NARGS(n) if (nargs != n) { success = 0; break; } #define ACB_FUNCTION_1(acb_func) \ REQUIRE_NARGS(1) \ success = fexpr_get_acb_raw(res, arg, prec); \ acb_func(res, res, prec); \ break; #define ACB_FUNCTION_1_ANALYTIC_FLAG(acb_func) \ REQUIRE_NARGS(1) \ success = fexpr_get_acb_raw(res, arg, prec); \ acb_func(res, res, 0, prec); \ break; #define ACB_FUNCTION_2(acb_func) \ REQUIRE_NARGS(2) \ success = fexpr_get_acb_raw(res, arg, prec); \ if (success) \ { \ acb_init(t); \ fexpr_view_next(arg); \ success = fexpr_get_acb_raw(t, arg, prec); \ if (success) \ acb_func(res, res, t, prec); \ acb_clear(t); \ } \ break; int fexpr_get_acb_raw(acb_t res, const fexpr_t expr, slong prec) { if (fexpr_is_integer(expr)) { fmpz_t c; fmpz_init(c); fexpr_get_fmpz(c, expr); acb_set_round_fmpz(res, c, prec); fmpz_clear(c); return 1; } else if (fexpr_is_atom(expr)) { ulong op; if (!fexpr_is_any_builtin_symbol(expr)) { acb_indeterminate(res); return 0; } /* todo: clean up these cases */ op = FEXPR_BUILTIN_ID(expr->data[0]); if (op == FEXPR_Pi) { acb_const_pi(res, prec); return 1; } if (op == FEXPR_NumberI) { acb_onei(res); return 1; } if (op == FEXPR_NumberE) { arb_const_e(acb_realref(res), prec); arb_zero(acb_imagref(res)); return 1; } if (op == FEXPR_Euler) { arb_const_euler(acb_realref(res), prec); arb_zero(acb_imagref(res)); return 1; } if (op == FEXPR_CatalanConstant) { arb_const_catalan(acb_realref(res), prec); arb_zero(acb_imagref(res)); return 1; } if (op == FEXPR_GoldenRatio) { arb_sqrt_ui(acb_realref(res), 5, prec); arb_add_ui(acb_realref(res), acb_realref(res), 1, prec); arb_mul_2exp_si(acb_realref(res), acb_realref(res), -1); arb_zero(acb_imagref(res)); return 1; } acb_indeterminate(res); return 0; } else { slong nargs; fmpz_t n, m; acb_t t, u, v, w; fexpr_t func; fexpr_t arg; fexpr_builtin_symbol op; slong i; int success = 0; nargs = fexpr_nargs(expr); fexpr_view_func(func, expr); if (!fexpr_is_any_builtin_symbol(func)) { acb_indeterminate(res); return 0; } if (nargs > 0) fexpr_view_arg(arg, expr, 0); op = FEXPR_BUILTIN_ID(func->data[0]); switch (op) { case FEXPR_Abs: REQUIRE_NARGS(1) success = fexpr_get_acb_raw(res, arg, prec); acb_abs(acb_realref(res), res, prec); arb_zero(acb_imagref(res)); break; case FEXPR_Acos: ACB_FUNCTION_1(acb_acos) case FEXPR_Acosh: ACB_FUNCTION_1(acb_acosh) case FEXPR_Add: if (nargs == 0) { acb_zero(res); } else if (nargs == 1) { success = fexpr_get_acb_raw(res, arg, prec); } else { acb_init(t); success = fexpr_get_acb_raw(res, arg, prec); for (i = 1; success && i < nargs; i++) { fexpr_view_next(arg); success = fexpr_get_acb_raw(t, arg, prec); acb_add(res, res, t, prec); } acb_clear(t); } break; case FEXPR_AiryAi: REQUIRE_NARGS(1) success = fexpr_get_acb_raw(res, arg, prec); acb_hypgeom_airy(res, NULL, NULL, NULL, res, prec); break; case FEXPR_AiryBi: REQUIRE_NARGS(1) success = fexpr_get_acb_raw(res, arg, prec); acb_hypgeom_airy(NULL, res, NULL, NULL, res, prec); break; case FEXPR_Arg: REQUIRE_NARGS(1) success = fexpr_get_acb_raw(res, arg, prec); acb_arg(acb_realref(res), res, prec); arb_zero(acb_imagref(res)); break; case FEXPR_Asin: ACB_FUNCTION_1(acb_asin) case FEXPR_Asinh: ACB_FUNCTION_1(acb_asinh) case FEXPR_Atan: ACB_FUNCTION_1(acb_atan) case FEXPR_Atanh: ACB_FUNCTION_1(acb_atanh) case FEXPR_BesselI: ACB_FUNCTION_2(acb_hypgeom_bessel_i) case FEXPR_BesselJ: ACB_FUNCTION_2(acb_hypgeom_bessel_j) case FEXPR_BesselK: ACB_FUNCTION_2(acb_hypgeom_bessel_k) case FEXPR_BesselY: ACB_FUNCTION_2(acb_hypgeom_bessel_y) case FEXPR_Ceil: ACB_FUNCTION_1_ANALYTIC_FLAG(acb_real_ceil) case FEXPR_Conjugate: REQUIRE_NARGS(1) success = fexpr_get_acb_raw(res, arg, prec); acb_conj(res, res); break; case FEXPR_Cos: ACB_FUNCTION_1(acb_cos) case FEXPR_Cosh: ACB_FUNCTION_1(acb_cosh) case FEXPR_DedekindEta: ACB_FUNCTION_1(acb_modular_eta) case FEXPR_Div: ACB_FUNCTION_2(acb_div) case FEXPR_Erf: ACB_FUNCTION_1(acb_hypgeom_erf) case FEXPR_Erfc: ACB_FUNCTION_1(acb_hypgeom_erfc) case FEXPR_Erfi: ACB_FUNCTION_1(acb_hypgeom_erfi) case FEXPR_Exp: ACB_FUNCTION_1(acb_exp) case FEXPR_Floor: ACB_FUNCTION_1_ANALYTIC_FLAG(acb_real_floor) case FEXPR_Gamma: ACB_FUNCTION_1(acb_gamma) case FEXPR_HurwitzZeta: ACB_FUNCTION_2(acb_hurwitz_zeta) case FEXPR_Im: REQUIRE_NARGS(1) success = fexpr_get_acb_raw(res, arg, prec); arb_swap(acb_realref(res), acb_imagref(res)); arb_zero(acb_imagref(res)); break; case FEXPR_JacobiTheta: REQUIRE_NARGS(3) { fmpz_init(n); success = fexpr_get_fmpz(n, arg); if (success) success = (*n == 1 || *n == 2 || *n == 3 || *n == 4); if (success) { fexpr_view_next(arg); success = fexpr_get_acb_raw(res, arg, prec); if (success) { acb_init(t); fexpr_view_next(arg); success = fexpr_get_acb_raw(t, arg, prec); if (success) { acb_init(u); acb_init(v); acb_init(w); if (*n == 1) acb_modular_theta(res, t, u, v, res, t, prec); else if (*n == 2) acb_modular_theta(t, res, u, v, res, t, prec); else if (*n == 3) acb_modular_theta(t, u, res, v, res, t, prec); else acb_modular_theta(t, u, v, res, res, t, prec); acb_clear(u); acb_clear(v); acb_clear(w); } acb_clear(t); } } fmpz_clear(n); } break; case FEXPR_LambertW: if (nargs == 1) { fmpz_init(n); success = fexpr_get_acb_raw(res, arg, prec); if (success) acb_lambertw(res, res, n, 0, prec); fmpz_clear(n); } else if (nargs == 2) { fmpz_init(n); success = fexpr_get_fmpz(n, arg); if (success) { fexpr_view_next(arg); success = fexpr_get_acb_raw(res, arg, prec); if (success) acb_lambertw(res, res, n, 0, prec); } fmpz_clear(n); } break; case FEXPR_Log: ACB_FUNCTION_1(acb_log) case FEXPR_LogGamma: ACB_FUNCTION_1(acb_lgamma) case FEXPR_Mul: if (nargs == 0) { acb_one(res); } else if (nargs == 1) { success = fexpr_get_acb_raw(res, arg, prec); } else { acb_init(t); success = fexpr_get_acb_raw(res, arg, prec); for (i = 1; success && i < nargs; i++) { fexpr_view_next(arg); success = fexpr_get_acb_raw(t, arg, prec); acb_mul(res, res, t, prec); } acb_clear(t); } break; case FEXPR_Neg: REQUIRE_NARGS(1) success = fexpr_get_acb_raw(res, arg, prec); acb_neg(res, res); break; case FEXPR_Pos: REQUIRE_NARGS(1) success = fexpr_get_acb_raw(res, arg, prec); break; case FEXPR_Pow: ACB_FUNCTION_2(acb_pow) /* todo: acb_polygamma */ case FEXPR_DigammaFunction: ACB_FUNCTION_1(acb_digamma) case FEXPR_Re: REQUIRE_NARGS(1) success = fexpr_get_acb_raw(res, arg, prec); arb_zero(acb_imagref(res)); break; case FEXPR_RiemannZeta: ACB_FUNCTION_1(acb_zeta) case FEXPR_Root: ACB_FUNCTION_2(_acb_root) case FEXPR_RootOfUnity: if (nargs == 1 || nargs == 2) { fmpq_t q; fmpz_init(n); fmpz_init(m); fmpz_one(m); success = fexpr_get_fmpz(n, arg); success = success && (fmpz_sgn(n) >= 1); if (success && nargs == 2) { fexpr_view_next(arg); success = fexpr_get_fmpz(m, arg); } if (success) { fmpz_mul_2exp(m, m, 1); *fmpq_denref(q) = *n; *fmpq_numref(q) = *m; arb_sin_cos_pi_fmpq(acb_imagref(res), acb_realref(res), q, prec); } } break; case FEXPR_Sign: ACB_FUNCTION_1(acb_sgn) case FEXPR_Sin: ACB_FUNCTION_1(acb_sin) case FEXPR_Sinh: ACB_FUNCTION_1(acb_sinh) case FEXPR_Sqrt: ACB_FUNCTION_1(acb_sqrt) case FEXPR_Sub: if (nargs == 0) { acb_zero(res); } else if (nargs == 1) { success = fexpr_get_acb_raw(res, arg, prec); } else { acb_init(t); success = fexpr_get_acb_raw(res, arg, prec); for (i = 1; success && i < nargs; i++) { fexpr_view_next(arg); success = fexpr_get_acb_raw(t, arg, prec); acb_sub(res, res, t, prec); } acb_clear(t); } break; case FEXPR_Tan: ACB_FUNCTION_1(acb_tan) case FEXPR_Tanh: ACB_FUNCTION_1(acb_tanh) default: success = 0; } if (!success || !acb_is_finite(res)) { success = 0; acb_indeterminate(res); } return success; } } int fexpr_get_acb_with_accuracy(acb_t res, const fexpr_t expr, slong prec, ulong flags) { slong wp, initial, maxprec; int success = 0; initial = prec * 1.05 + 20; maxprec = FLINT_MAX(4096, 4 * initial); for (wp = initial; wp < maxprec; wp *= 2) { success = fexpr_get_acb_raw(res, expr, wp); if (acb_rel_accuracy_bits(res) >= prec) break; } return success; } char * fexpr_get_decimal_str(const fexpr_t expr, slong digits, ulong flags) { calcium_stream_t t; acb_t v; digits = FLINT_MAX(digits, 1); acb_init(v); calcium_stream_init_str(t); if (fexpr_get_acb_with_accuracy(v, expr, digits * 3.333 + 1, 0)) calcium_write_acb(t, v, digits, ARB_STR_NO_RADIUS); else calcium_write(t, "?"); acb_clear(v); return t->s; } /* todo: implement void fexpr_set_acb(fexpr_t res, const acb_t x); */ calcium-0.4.1/fexpr/print.c000066400000000000000000000106211407704557200155700ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" void fexpr_write(calcium_stream_t stream, const fexpr_t expr) { ulong type = FEXPR_TYPE(expr->data[0]); switch (type) { case FEXPR_TYPE_SMALL_INT: { slong c = ((slong) (expr->data[0])) >> FEXPR_TYPE_BITS; calcium_write_si(stream, c); } break; case FEXPR_TYPE_SMALL_SYMBOL: { slong i; if (((expr->data[0] >> 8) & 0xff) == 0) { calcium_write(stream, fexpr_builtin_table[expr->data[0] >> 16].string); } else { char tmp[FEXPR_SMALL_SYMBOL_LEN + 1]; tmp[FEXPR_SMALL_SYMBOL_LEN] = '\0'; for (i = 0; i < FEXPR_SMALL_SYMBOL_LEN; i++) { char c = expr->data[0] >> ((i + 1) * 8); tmp[i] = c; if (c == '\0') break; } calcium_write(stream, tmp); } } break; case FEXPR_TYPE_BIG_SYMBOL: { calcium_write(stream, (const char *) (expr->data + 1)); } break; case FEXPR_TYPE_SMALL_STRING: { slong i; char tmp[FEXPR_SMALL_SYMBOL_LEN + 3]; /* todo: escape string */ tmp[FEXPR_SMALL_SYMBOL_LEN] = '\0'; for (i = 0; i < FEXPR_SMALL_SYMBOL_LEN; i++) { char c = expr->data[0] >> ((i + 1) * 8); tmp[i] = c; if (c == '\0') break; } calcium_write(stream, "\""); calcium_write(stream, tmp); calcium_write(stream, "\""); } break; case FEXPR_TYPE_BIG_STRING: { calcium_write(stream, "\""); /* todo: escape string */ calcium_write(stream, (const char *) (expr->data + 1)); calcium_write(stream, "\""); } break; case FEXPR_TYPE_BIG_INT_NEG: case FEXPR_TYPE_BIG_INT_POS: /* todo: print without copying */ { fmpz_t c; fmpz_init(c); fexpr_get_fmpz(c, expr); calcium_write_fmpz(stream, c); fmpz_clear(c); } break; case FEXPR_TYPE_CALL0: case FEXPR_TYPE_CALL1: case FEXPR_TYPE_CALL2: case FEXPR_TYPE_CALL3: case FEXPR_TYPE_CALL4: case FEXPR_TYPE_CALLN: { fexpr_t t; ulong * ptr; slong i, num; if (type == FEXPR_TYPE_CALLN) { num = expr->data[1]; ptr = expr->data + expr->data[2]; } else { ptr = expr->data + FEXPR_HEADER_SIZE; num = type - FEXPR_TYPE_CALL0; } t->data = ptr; t->alloc = 1; fexpr_write(stream, t); t->data += fexpr_size(t); calcium_write(stream, "("); for (i = 0; i < num; i++) { fexpr_write(stream, t); t->data += fexpr_size(t); if (i < num - 1) calcium_write(stream, ", "); } calcium_write(stream, ")"); } break; default: calcium_write(stream, "?UNKNOWN?"); } } void fexpr_print(const fexpr_t expr) { calcium_stream_t t; calcium_stream_init_file(t, stdout); fexpr_write(t, expr); } char * fexpr_get_str(const fexpr_t expr) { calcium_stream_t t; calcium_stream_init_str(t); fexpr_write(t, expr); return t->s; } calcium-0.4.1/fexpr/replace.c000066400000000000000000000113101407704557200160430ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" /* Sets res_view to a view of expr replaced by {xs, ys, len} and returns whether any replacement has been made. If no replacement has been made, res_view will refer to the data of expr, with an alloc field of 0. If expr as a whole has been replaced with some entry in ys, res_view will refer to the data of that value in ys, also with an alloc field of 0. Otherwise, expr will be initialized to a new expression, with a nonzero alloc field. */ int _fexpr_replace_vec(fexpr_t res_view, const fexpr_t expr, fexpr_srcptr xs, fexpr_srcptr ys, slong len) { slong i, nargs; fexpr_t func, new_func, arg; fexpr_struct tmp_args[4]; fexpr_ptr args; int changed; for (i = 0; i < len; i++) { if (fexpr_equal(expr, xs + i)) { res_view->data = ys[i].data; res_view->alloc = 0; return 1; } } if (fexpr_is_atom(expr)) { res_view->data = expr->data; res_view->alloc = 0; return 0; } nargs = fexpr_nargs(expr); fexpr_view_func(func, expr); changed = _fexpr_replace_vec(new_func, func, xs, ys, len); if (nargs >= 5) args = flint_malloc(sizeof(fexpr_struct) * nargs); else args = tmp_args; if (nargs >= 1) { fexpr_view_arg(arg, expr, 0); for (i = 0; i < nargs; i++) { changed |= _fexpr_replace_vec(args + i, arg, xs, ys, len); if (i < nargs - 1) fexpr_view_next(arg); } } if (changed) { fexpr_init(res_view); fexpr_call_vec(res_view, new_func, args, nargs); if (new_func->alloc != 0) flint_free(new_func->data); for (i = 0; i < nargs; i++) { if (args[i].alloc != 0) flint_free(args[i].data); } } else { res_view->data = expr->data; res_view->alloc = 0; } if (nargs >= 5) flint_free(args); return changed; } int fexpr_replace_vec(fexpr_t res, const fexpr_t expr, const fexpr_vec_t xs, const fexpr_vec_t ys) { int changed; slong num_rules; fexpr_t res_view; num_rules = xs->length; if (num_rules != ys->length) { flint_printf("fexpr_replace_vec: vectors don't match\n"); flint_abort(); } if (num_rules == 0) { fexpr_set(res, expr); return 0; } changed = _fexpr_replace_vec(res_view, expr, xs->entries, ys->entries, num_rules); if (changed) { if (res_view->alloc != 0) { /* We have new data */ fexpr_swap(res, res_view); fexpr_clear(res_view); } else { /* Must be a view of some ys; we assume that res is not aliased with any entry in ys. */ fexpr_set(res, res_view); } } else { fexpr_set(res, expr); } return changed; } int fexpr_replace(fexpr_t res, const fexpr_t expr, const fexpr_t x, const fexpr_t y) { int changed; fexpr_t res_view; changed = _fexpr_replace_vec(res_view, expr, x, y, 1); if (changed) { if (res_view->alloc != 0) { /* We have new data */ fexpr_swap(res, res_view); fexpr_clear(res_view); } else { /* Must be a view of some ys; we assume that res is not aliased with any entry in ys. */ fexpr_set(res, res_view); } } else { fexpr_set(res, expr); } return changed; } int fexpr_replace2(fexpr_t res, const fexpr_t expr, const fexpr_t x1, const fexpr_t y1, const fexpr_t x2, const fexpr_t y2) { int changed; fexpr_t res_view; fexpr_struct tmp[4]; tmp[0] = *x1; tmp[1] = *x2; tmp[2] = *y1; tmp[3] = *y2; changed = _fexpr_replace_vec(res_view, expr, tmp, tmp + 2, 2); if (changed) { if (res_view->alloc != 0) { /* We have new data */ fexpr_swap(res, res_view); fexpr_clear(res_view); } else { /* Must be a view of some ys; we assume that res is not aliased with any entry in ys. */ fexpr_set(res, res_view); } } else { fexpr_set(res, expr); } return changed; } calcium-0.4.1/fexpr/set_arf.c000066400000000000000000000042741407704557200160660ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" void fexpr_set_arf(fexpr_t res, const arf_t x) { if (arf_is_zero(x)) { fexpr_zero(res); } else if (arf_is_pos_inf(x)) { fexpr_set_symbol_builtin(res, FEXPR_Infinity); } else if (arf_is_neg_inf(x)) { fexpr_set_symbol_builtin(res, FEXPR_Infinity); fexpr_neg(res, res); } else if (arf_is_nan(x)) { fexpr_set_symbol_builtin(res, FEXPR_Undefined); } else { fmpz_t m, e; fmpz_init(m); fmpz_init(e); arf_get_fmpz_2exp(m, e, x); if (0 <= *e && *e <= 20) { fmpz_mul_2exp(m, m, *e); fexpr_set_fmpz(res, m); } else if (-8 <= *e && *e < 0) { fmpq_t t; *fmpq_numref(t) = *m; *fmpq_denref(t) = (1 << (-*e)); fexpr_set_fmpq(res, t); } else if (fmpz_is_pm1(m)) { fexpr_t base, exp; fexpr_init(base); fexpr_init(exp); fexpr_set_si(base, 2); fexpr_set_fmpz(exp, e); fexpr_pow(res, base, exp); if (!fmpz_is_one(m)) fexpr_neg(res, res); fexpr_clear(base); fexpr_clear(exp); } else { fexpr_t mantissa, base, exp; fexpr_init(mantissa); fexpr_init(base); fexpr_init(exp); fexpr_set_si(base, 2); fexpr_set_fmpz(exp, e); fexpr_pow(res, base, exp); fexpr_set_fmpz(mantissa, m); fexpr_mul(base, mantissa, res); fexpr_swap(res, base); fexpr_clear(mantissa); fexpr_clear(base); fexpr_clear(exp); } fmpz_clear(m); fmpz_clear(e); } } calcium-0.4.1/fexpr/set_d.c000066400000000000000000000031741407704557200155370ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" void fexpr_set_d(fexpr_t res, double x) { arf_t t; arf_init(t); arf_set_d(t, x); /* no need to free */ fexpr_set_arf(res, t); } void fexpr_set_re_im_d(fexpr_t res, double x, double y) { if (y == 0.0) { fexpr_set_d(res, x); } else if (x == 0.0) { if (y == 1.0) { fexpr_set_symbol_builtin(res, FEXPR_NumberI); } else if (y == -1.0) { fexpr_set_symbol_builtin(res, FEXPR_NumberI); fexpr_neg(res, res); } else { fexpr_t im, t; fexpr_init(im); fexpr_init(t); fexpr_set_d(im, y); fexpr_set_symbol_builtin(t, FEXPR_NumberI); fexpr_mul(res, im, t); fexpr_clear(im); fexpr_clear(t); } } else { fexpr_t re, im, t; fexpr_init(re); fexpr_init(im); fexpr_init(t); fexpr_set_d(re, x); fexpr_set_d(im, y); fexpr_set_symbol_builtin(t, FEXPR_NumberI); fexpr_mul(res, im, t); fexpr_swap(t, res); fexpr_add(res, re, t); fexpr_clear(re); fexpr_clear(im); fexpr_clear(t); } } calcium-0.4.1/fexpr/set_fmpq.c000066400000000000000000000026121407704557200162530ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" void fexpr_set_fmpq(fexpr_t res, const fmpq_t x) { if (fmpz_is_one(fmpq_denref(x))) { fexpr_set_fmpz(res, fmpq_numref(x)); } else { slong p, q; p = *fmpq_numref(x); q = *fmpq_denref(x); if (p >= FEXPR_COEFF_MIN && p <= FEXPR_COEFF_MAX && q >= FEXPR_COEFF_MIN && q <= FEXPR_COEFF_MAX) { fexpr_fit_size(res, 4); res->data[0] = FEXPR_TYPE_CALL2 | (4 << FEXPR_TYPE_BITS); res->data[1] = FEXPR_SYMBOL_Div; res->data[2] = p << FEXPR_TYPE_BITS; res->data[3] = q << FEXPR_TYPE_BITS; } else /* todo: copy directly without temporaries */ { fexpr_t a, b; fexpr_init(a); fexpr_init(b); fexpr_set_fmpz(a, fmpq_numref(x)); fexpr_set_fmpz(b, fmpq_denref(x)); fexpr_div(res, a, b); fexpr_clear(a); fexpr_clear(b); } } } calcium-0.4.1/fexpr/set_fmpz.c000066400000000000000000000015731407704557200162710ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" void fexpr_set_fmpz(fexpr_t res, const fmpz_t c) { if (!COEFF_IS_MPZ(*c)) { fexpr_set_si(res, *c); } else { slong nlimbs; __mpz_struct * z = COEFF_TO_PTR(*c); nlimbs = FLINT_ABS(z->_mp_size); fexpr_fit_size(res, 1 + nlimbs); res->data[0] = ((z->_mp_size > 0) ? FEXPR_TYPE_BIG_INT_POS : FEXPR_TYPE_BIG_INT_NEG) | ((1 + nlimbs) << FEXPR_TYPE_BITS); flint_mpn_copyi(res->data + 1, z->_mp_d, nlimbs); } } calcium-0.4.1/fexpr/set_fmpz_mpoly.c000066400000000000000000000061221407704557200175040ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" /* Sets *res* to an expression for the multivariate polynomial *poly* using the expressions in *vars* as variables. If *vars* is *NULL*, the symbols *x1*, *x2*, ..., *xn* are used. */ void fexpr_set_fmpz_mpoly(fexpr_t res, const fmpz_mpoly_t poly, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx) { slong len, nvars, i, j, factors_len; fexpr_ptr terms; fexpr_ptr factors; fexpr_t op, t; ulong * exp; nvars = ctx->minfo->nvars; len = poly->length; if (len == 0) { fexpr_zero(res); return; } if (fmpz_mpoly_is_fmpz(poly, ctx)) { fexpr_set_fmpz(res, poly->coeffs); return; } if (vars == NULL) { fexpr_vec_t v; fexpr_vec_init(v, nvars); /* FIXME */ for (i = 0; i < nvars; i++) { fexpr_vec_entry(v, i)->data[0] = FEXPR_TYPE_SMALL_SYMBOL | ('x' << 8) | (('1' + i) << 16); } fexpr_set_fmpz_mpoly(res, poly, v, ctx); fexpr_vec_clear(v); return; } exp = flint_malloc(sizeof(ulong) * nvars); len = poly->length; fexpr_init(t); fexpr_init(op); factors = _fexpr_vec_init(nvars + 1); /* todo: just allocate one array */ terms = _fexpr_vec_init(len); fexpr_set_symbol_str(op, "Mul"); for (i = 0; i < len; i++) { int constant_term; fmpz_mpoly_get_term_exp_ui(exp, poly, i, ctx); factors_len = 0; constant_term = (i == len - 1); for (j = 0; constant_term && j < nvars; j++) if (exp[j] != 0) constant_term = 0; if (!fmpz_is_one(poly->coeffs + i) || constant_term) { fexpr_set_fmpz(factors, poly->coeffs + i); factors_len = 1; } for (j = 0; j < nvars; j++) { if (exp[j] != 0) { if (exp[j] == 1) { fexpr_set(factors + factors_len, fexpr_vec_entry(vars, j)); } else { fexpr_set_ui(t, exp[j]); fexpr_pow(factors + factors_len, fexpr_vec_entry(vars, j), t); } factors_len++; } } if (factors_len == 1) fexpr_set(terms + i, factors); else { fexpr_call_vec(terms + i, op, factors, factors_len); } } if (len == 1) { fexpr_swap(res, terms); } else { fexpr_set_symbol_str(op, "Add"); fexpr_call_vec(res, op, terms, len); } flint_free(exp); _fexpr_vec_clear(factors, nvars + 1); _fexpr_vec_clear(terms, len); fexpr_clear(op); fexpr_clear(t); } calcium-0.4.1/fexpr/set_fmpz_mpoly_q.c000066400000000000000000000017351407704557200200310ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" void fexpr_set_fmpz_mpoly_q(fexpr_t res, const fmpz_mpoly_q_t frac, const fexpr_vec_t vars, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_one(fmpz_mpoly_q_denref(frac), ctx)) { fexpr_set_fmpz_mpoly(res, fmpz_mpoly_q_numref(frac), vars, ctx); } else { fexpr_t p, q; fexpr_init(p); fexpr_init(q); fexpr_set_fmpz_mpoly(p, fmpz_mpoly_q_numref(frac), vars, ctx); fexpr_set_fmpz_mpoly(q, fmpz_mpoly_q_denref(frac), vars, ctx); fexpr_div(res, p, q); fexpr_clear(p); fexpr_clear(q); } } calcium-0.4.1/fexpr/set_si.c000066400000000000000000000014001407704557200157150ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" void fexpr_set_si(fexpr_t res, slong c) { if (c >= FEXPR_COEFF_MIN && c <= FEXPR_COEFF_MAX) { res->data[0] = (c << FEXPR_TYPE_BITS); } else { fexpr_fit_size(res, 2); res->data[0] = ((c > 0) ? FEXPR_TYPE_BIG_INT_POS : FEXPR_TYPE_BIG_INT_NEG) | (2 << FEXPR_TYPE_BITS); res->data[1] = (c > 0) ? c : -c; } } calcium-0.4.1/fexpr/set_string.c000066400000000000000000000022051407704557200166140ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" void fexpr_set_string(fexpr_t res, const char * s) { slong i, len; len = strlen(s); if (len <= FEXPR_SMALL_SYMBOL_LEN) { ulong data; data = FEXPR_TYPE_SMALL_STRING; for (i = 0; i < len; i++) data |= (((ulong) s[i]) << ((i + 1) * 8)); res->data[0] = data; } else { slong data_size; data_size = len + 1; data_size = (data_size + sizeof(ulong) - 1) / sizeof(ulong); fexpr_fit_size(res, data_size + 1); res->data[0] = FEXPR_TYPE_BIG_STRING | ((data_size + 1) << FEXPR_TYPE_BITS); res->data[data_size] = 0; /* zero pad for consistency */ memcpy((char *) (res->data + 1), s, len + 1); } } calcium-0.4.1/fexpr/set_symbol_str.c000066400000000000000000000024461407704557200175120ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" void fexpr_set_symbol_str(fexpr_t res, const char * s) { slong i, len; i = fexpr_builtin_lookup(s); if (i != -1) { res->data[0] = FEXPR_TYPE_SMALL_SYMBOL | (i << 16); return; } len = strlen(s); if (len <= FEXPR_SMALL_SYMBOL_LEN) { slong i; ulong data; data = FEXPR_TYPE_SMALL_SYMBOL; for (i = 0; i < len; i++) data |= (((ulong) s[i]) << ((i + 1) * 8)); res->data[0] = data; } else { slong data_size; data_size = len + 1; data_size = (data_size + sizeof(ulong) - 1) / sizeof(ulong); fexpr_fit_size(res, data_size + 1); res->data[0] = FEXPR_TYPE_BIG_SYMBOL | ((data_size + 1) << FEXPR_TYPE_BITS); res->data[data_size] = 0; /* zero pad for consistency */ memcpy((char *) (res->data + 1), s, len + 1); } } calcium-0.4.1/fexpr/set_ui.c000066400000000000000000000012641407704557200157270ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" void fexpr_set_ui(fexpr_t res, ulong c) { if (c <= FEXPR_COEFF_MAX) { res->data[0] = (c << FEXPR_TYPE_BITS); } else { fexpr_fit_size(res, 2); res->data[0] = FEXPR_TYPE_BIG_INT_POS | (2 << FEXPR_TYPE_BITS); res->data[1] = c; } } calcium-0.4.1/fexpr/test/000077500000000000000000000000001407704557200152475ustar00rootroot00000000000000calcium-0.4.1/fexpr/test/t-builtins.c000066400000000000000000000034511407704557200175100ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" #include "fexpr.h" #include "fexpr_builtin.h" int main() { flint_rand_t state; flint_printf("builtins..."); fflush(stdout); flint_randinit(state); { slong i, j; for (i = 0; i < FEXPR_BUILTIN_LENGTH; i++) { if (fexpr_builtin_table[i].symbol != i) { flint_printf("FAIL (missing)\n"); flint_printf("%s\n", fexpr_builtin_name(i)); flint_abort(); } if (i < FEXPR_BUILTIN_LENGTH - 1 && strcmp(fexpr_builtin_name(i), fexpr_builtin_name(i + 1)) >= 0) { flint_printf("FAIL (order)\n"); flint_printf("%s\n", fexpr_builtin_name(i)); flint_printf("%s\n", fexpr_builtin_name(i + 1)); flint_abort(); } j = fexpr_builtin_lookup(fexpr_builtin_name(i)); if (i != j) { flint_printf("FAIL (lookup)\n"); flint_printf("%s\n", fexpr_builtin_name(i)); flint_abort(); } } } if (fexpr_builtin_lookup("") != -1 || fexpr_builtin_lookup("FooBarBaz") != -1 || fexpr_builtin_lookup("ZZZZZZZ") != -1) { flint_printf("FAIL (lookup)\n"); flint_abort(); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fexpr/test/t-call_vec.c000066400000000000000000000045011407704557200174240ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" #include "fexpr.h" int main() { slong iter; flint_rand_t state; flint_printf("call_vec..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fexpr_t f, f2, f3, g, v, a; fexpr_ptr args; fmpz_t c; slong i, len; len = n_randint(state, 20); fmpz_init(c); fexpr_init(f); fexpr_init(f2); fexpr_init(g); fexpr_init(a); args = _fexpr_vec_init(len); if (n_randint(state, 2)) fexpr_set_symbol_str(f, "Foo"); else fexpr_set_symbol_str(f, "FooVeryLongSymbolName"); for (i = 0; i < len; i++) { fmpz_randtest(c, state, 200); fexpr_set_fmpz(args + i, c); } fexpr_call_vec(g, f, args, len); for (i = 0; i < len; i++) { fexpr_func(f2, g); fexpr_view_func(f3, g); fexpr_arg(a, g, i); fexpr_view_arg(v, g, i); if (fexpr_nargs(g) != len || !fexpr_equal(f, f2) || !fexpr_equal(f, f3) || !fexpr_equal(a, args + i) || !fexpr_equal(v, args + i)) { flint_printf("FAIL\n\n"); flint_printf("len = %wd\n", len); flint_printf("g = "); fexpr_print(g); printf("\n"); flint_printf("arg = "); fexpr_print(args + i); printf("\n"); flint_printf("a = "); fexpr_print(a); printf("\n"); flint_printf("v = "); fexpr_print(v); printf("\n"); flint_printf("f2 = "); fexpr_print(f2); printf("\n"); flint_abort(); } } fexpr_clear(f); fexpr_clear(f2); fexpr_clear(g); fexpr_clear(a); _fexpr_vec_clear(args, len); fmpz_clear(c); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fexpr/test/t-replace.c000066400000000000000000000144571407704557200173020ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" #include "fexpr.h" #include "fexpr_builtin.h" void fexpr_randtest_atom1(fexpr_t expr, flint_rand_t state) { if (n_randint(state, 2)) { if (n_randint(state, 10) == 5) fexpr_set_si(expr, (slong) n_randtest(state)); else fexpr_set_si(expr, ((slong) n_randint(state, 3)) - 1); } else { if (n_randint(state, 2)) fexpr_set_symbol_builtin(expr, FEXPR_alpha); else fexpr_set_symbol_builtin(expr, FEXPR_beta); } } void fexpr_randtest1(fexpr_t expr, flint_rand_t state, slong max_leaves, slong max_depth) { if (max_leaves <= 1 || max_depth <= 1 || n_randint(state, 10) == 0) { fexpr_randtest_atom1(expr, state); } else { slong i, nargs; fexpr_t f; fexpr_ptr args; fexpr_init(f); fexpr_randtest1(f, state, max_leaves / 4, max_depth - 1); max_leaves -= fexpr_num_leaves(f); nargs = n_randint(state, 1 + FLINT_MIN(5, max_leaves / max_depth)); args = _fexpr_vec_init(nargs); for (i = 0; i < nargs; i++) { fexpr_randtest1(args + i, state, max_leaves, max_depth - 1); max_leaves -= fexpr_num_leaves(args + i); } fexpr_call_vec(expr, f, args, nargs); _fexpr_vec_clear(args, nargs); fexpr_clear(f); } } int fexpr_replace_vec_naive(fexpr_t res, const fexpr_t expr, const fexpr_vec_t xs, const fexpr_vec_t ys) { slong i, num_rules; num_rules = xs->length; if (num_rules != ys->length) { flint_printf("fexpr_replace_vec: vectors don't match\n"); flint_abort(); } for (i = 0; i < num_rules; i++) { if (fexpr_equal(expr, xs->entries + i)) { fexpr_set(res, ys->entries + i); return 1; } } if (fexpr_is_atom(expr)) { fexpr_set(res, expr); return 0; } else { fexpr_ptr args; fexpr_t func, view; slong nargs; int changed; nargs = fexpr_nargs(expr); args = NULL; fexpr_init(func); fexpr_view_func(view, expr); changed = fexpr_replace_vec_naive(func, view, xs, ys); if (nargs >= 1) { args = _fexpr_vec_init(nargs); fexpr_view_arg(view, expr, 0); for (i = 0; i < nargs; i++) { changed |= fexpr_replace_vec_naive(args + i, view, xs, ys); if (i < nargs - 1) fexpr_view_next(view); } fexpr_call_vec(res, func, args, nargs); _fexpr_vec_clear(args, nargs); } else { fexpr_call0(res, func); } fexpr_clear(func); return changed; } } int main() { slong iter; flint_rand_t state; flint_printf("replace..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fexpr_t expr, res1, res2, res3; fexpr_vec_t xs, ys; slong i, len; int changed1, changed2, changed3; fexpr_init(expr); fexpr_init(res1); fexpr_init(res2); fexpr_init(res3); fexpr_randtest1(expr, state, 1 + n_randint(state, 100), 2 + n_randint(state, 10)); fexpr_randtest1(res1, state, 5, 2 + n_randint(state, 5)); fexpr_randtest1(res2, state, 5, 2 + n_randint(state, 5)); len = n_randint(state, 4); fexpr_vec_init(xs, len); fexpr_vec_init(ys, len); for (i = 0; i < len; i++) { fexpr_randtest1(xs->entries + i, state, 1 + n_randint(state, 3), 1 + n_randint(state, 2)); fexpr_randtest1(ys->entries + i, state, 1 + n_randint(state, 10), 2 + n_randint(state, 5)); } if (xs->length == 1 && n_randint(state, 2)) { changed1 = fexpr_replace(res1, expr, xs->entries, ys->entries); /* also test contains() */ if (n_randint(state, 2)) changed1 = fexpr_contains(expr, xs->entries); } else changed1 = fexpr_replace_vec(res1, expr, xs, ys); fexpr_set(res2, expr); if (xs->length == 1 && n_randint(state, 2)) changed2 = fexpr_replace(res2, res2, xs->entries, ys->entries); else changed2 = fexpr_replace_vec(res2, res2, xs, ys); changed3 = fexpr_replace_vec_naive(res3, expr, xs, ys); if ((changed1 != changed3) || !fexpr_equal(res1, res3)) { flint_printf("FAIL\n"); flint_printf("expr = "); fexpr_print(expr); flint_printf("\n\n"); flint_printf("xs = "); fexpr_vec_print(xs); flint_printf("\n\n"); flint_printf("ys = "); fexpr_vec_print(ys); flint_printf("\n\n"); flint_printf("res1 = "); fexpr_print(res1); flint_printf("\n\n"); flint_printf("res3 = "); fexpr_print(res3); flint_printf("\n\n"); flint_printf("changed1 = %d, changed3 = %d\n\n", changed1, changed3); flint_abort(); } if ((changed1 != changed2) || !fexpr_equal(res1, res2)) { flint_printf("FAIL (aliasing)\n"); flint_printf("expr = "); fexpr_print(expr); flint_printf("\n\n"); flint_printf("xs = "); fexpr_vec_print(xs); flint_printf("\n\n"); flint_printf("ys = "); fexpr_vec_print(ys); flint_printf("\n\n"); flint_printf("res1 = "); fexpr_print(res1); flint_printf("\n\n"); flint_printf("res2 = "); fexpr_print(res2); flint_printf("\n\n"); flint_printf("changed1 = %d, changed2 = %d\n\n", changed1, changed2); flint_abort(); } fexpr_vec_clear(xs); fexpr_vec_clear(ys); fexpr_clear(expr); fexpr_clear(res1); fexpr_clear(res2); fexpr_clear(res3); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fexpr/test/t-set_fmpz.c000066400000000000000000000026511407704557200175070ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" #include "fexpr.h" int main() { slong iter; flint_rand_t state; flint_printf("set_fmpz..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_t a, b; fexpr_t x; slong i; fmpz_init(a); fmpz_init(b); fexpr_init(x); for (i = 0; i < 5; i++) { fmpz_randtest(a, state, 300); fexpr_set_fmpz(x, a); fexpr_get_fmpz(b, x); if (!fmpz_equal(a, b)) { flint_printf("FAIL\n\n"); flint_printf("a = "); fmpz_print(a); printf("\n"); flint_printf("b = "); fmpz_print(b); printf("\n"); flint_printf("x = "); fexpr_print(x); printf("\n"); flint_abort(); } } fmpz_clear(a); fmpz_clear(b); fexpr_clear(x); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fexpr/test/t-write_latex.c000066400000000000000000000070111407704557200202020ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" #include "fexpr.h" #include "fexpr_builtin.h" void fexpr_randtest_atom(fexpr_t expr, flint_rand_t state) { if (n_randint(state, 2)) { fexpr_set_si(expr, (slong) n_randtest(state)); } else if (n_randint(state, 2)) { switch (n_randint(state, 10)) { case 0: fexpr_set_symbol_builtin(expr, FEXPR_For); break; case 1: fexpr_set_symbol_builtin(expr, FEXPR_Where); break; case 2: fexpr_set_symbol_builtin(expr, FEXPR_Def); break; case 3: fexpr_set_symbol_builtin(expr, FEXPR_Neg); break; case 4: fexpr_set_symbol_builtin(expr, FEXPR_Pos); break; case 5: fexpr_set_symbol_builtin(expr, FEXPR_Add); break; case 6: fexpr_set_symbol_builtin(expr, FEXPR_Sub); break; case 7: fexpr_set_symbol_builtin(expr, FEXPR_Mul); break; case 8: fexpr_set_symbol_builtin(expr, FEXPR_Div); break; default: fexpr_set_symbol_builtin(expr, FEXPR_Pow); break; } } else { fexpr_set_symbol_builtin(expr, n_randint(state, FEXPR_BUILTIN_LENGTH)); } } /* todo: doesn't actually respect max_leaves */ void fexpr_randtest_gibberish(fexpr_t expr, flint_rand_t state, slong max_leaves, slong max_depth) { if (max_leaves <= 1 || max_depth <= 1 || n_randint(state, 10) == 0) { fexpr_randtest_atom(expr, state); } else { slong i, nargs; fexpr_t f; fexpr_ptr args; fexpr_init(f); if (n_randint(state, 10) != 0) { fexpr_set_symbol_builtin(f, n_randint(state, FEXPR_BUILTIN_LENGTH)); } else { fexpr_randtest_gibberish(f, state, max_leaves / 4, max_depth - 1); max_leaves -= fexpr_num_leaves(f); } nargs = n_randint(state, 1 + FLINT_MIN(5, max_leaves / max_depth)); args = _fexpr_vec_init(nargs); for (i = 0; i < nargs; i++) { fexpr_randtest_gibberish(args + i, state, max_leaves, max_depth - 1); max_leaves -= fexpr_num_leaves(args + i); } fexpr_call_vec(expr, f, args, nargs); _fexpr_vec_clear(args, nargs); fexpr_clear(f); } } int main() { slong iter; flint_rand_t state; flint_printf("write_latex..."); fflush(stdout); flint_randinit(state); /* Generate gibberish and just check that we get valid strings */ for (iter = 0; iter < 100000 * calcium_test_multiplier(); iter++) { fexpr_t expr; char * s; ulong flags; slong len; fexpr_init(expr); fexpr_randtest_gibberish(expr, state, 2 + n_randint(state, 30), 2 + n_randint(state, 5)); flags = 0; if (n_randint(state, 2)) flags |= FEXPR_LATEX_SMALL; if (n_randint(state, 2)) flags |= FEXPR_LATEX_LOGIC; /* fexpr_print(expr); printf("\n\n"); */ s = fexpr_get_str_latex(expr, flags); len = strlen(s); len = len; flint_free(s); fexpr_clear(expr); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fexpr/write_latex.c000066400000000000000000003223061407704557200167710ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" void fexpr_write_latex_symbol(int * subscript, calcium_stream_t out, const fexpr_t expr, ulong flags); int _fexpr_is_symbol_with_trailing_underscore(const fexpr_t expr); const char * fexpr_get_symbol_str_pointer(char * tmp, const fexpr_t expr) { slong i; ulong head = expr->data[0]; if (FEXPR_TYPE(head) == FEXPR_TYPE_SMALL_SYMBOL) { if (((head >> 8) & 0xff) == 0) { i = head >> 16; return fexpr_builtin_table[i].string; } tmp[FEXPR_SMALL_SYMBOL_LEN] = '\0'; for (i = 0; i < FEXPR_SMALL_SYMBOL_LEN; i++) { tmp[i] = (head >> ((i + 1) * 8)); if (tmp[i] == '\0') break; } return tmp; } else if (FEXPR_TYPE(head) == FEXPR_TYPE_BIG_SYMBOL) { return (const char *) (expr->data + 1); } else { flint_printf("fexpr_get_symbol_str_pointer: a symbol is required\n"); flint_abort(); } } int _fexpr_is_symbol_with_trailing_underscore(const fexpr_t expr) { const char *s; char tmp[FEXPR_SMALL_SYMBOL_LEN + 1]; slong len; if (!fexpr_is_symbol(expr)) return 0; s = fexpr_get_symbol_str_pointer(tmp, expr); len = strlen(s); return (len > 1 && s[len - 1] == '_'); } int _fexpr_is_symbol_with_internal_underscore(const fexpr_t expr) { const char *s; char tmp[FEXPR_SMALL_SYMBOL_LEN + 1]; slong i, len; if (!fexpr_is_symbol(expr)) return 0; s = fexpr_get_symbol_str_pointer(tmp, expr); len = strlen(s); if (len >= 3) { for (i = 1; i < len - 1; i++) if (s[i] == '_') return i; } return 0; } /* static int fexpr_view_call0(fexpr_t func, const fexpr_t expr) { slong nargs; nargs = fexpr_nargs(expr); if (nargs != 0) return 0; fexpr_view_func(func, expr); return 1; } */ static int fexpr_view_call1(fexpr_t func, fexpr_t x1, const fexpr_t expr) { slong nargs; nargs = fexpr_nargs(expr); if (nargs != 1) return 0; fexpr_view_func(func, expr); *x1 = *func; fexpr_view_next(x1); return 1; } /* static int fexpr_view_call2(fexpr_t func, fexpr_t x1, fexpr_t x2, const fexpr_t expr) { slong nargs; nargs = fexpr_nargs(expr); if (nargs != 2) return 0; fexpr_view_func(func, expr); *x1 = *func; fexpr_view_next(x1); *x2 = *x1; fexpr_view_next(x2); return 1; } */ static int fexpr_view_call3(fexpr_t func, fexpr_t x1, fexpr_t x2, fexpr_t x3, const fexpr_t expr) { slong nargs; nargs = fexpr_nargs(expr); if (nargs != 3) return 0; fexpr_view_func(func, expr); *x1 = *func; fexpr_view_next(x1); *x2 = *x1; fexpr_view_next(x2); *x3 = *x2; fexpr_view_next(x3); return 1; } /* static int fexpr_view_call4(fexpr_t func, fexpr_t x1, fexpr_t x2, fexpr_t x3, fexpr_t x4, const fexpr_t expr) { slong nargs; nargs = fexpr_nargs(expr); if (nargs != 4) return 0; fexpr_view_func(func, expr); *x1 = *func; fexpr_view_next(x1); *x2 = *x1; fexpr_view_next(x2); *x3 = *x2; fexpr_view_next(x3); *x4 = *x3; fexpr_view_next(x4); return 1; } */ static int fexpr_need_parens_in_mul(const fexpr_t expr, slong arg_index) { if (fexpr_is_atom(expr)) { if (arg_index == 0) return 0; return fexpr_is_neg_integer(expr); } else { fexpr_t func; fexpr_view_func(func, expr); if (fexpr_is_builtin_symbol(func, FEXPR_Add)) return 1; if (fexpr_is_builtin_symbol(func, FEXPR_Sub)) return 1; if (fexpr_is_builtin_symbol(func, FEXPR_Neg)) return (arg_index != 0); if (fexpr_is_builtin_symbol(func, FEXPR_Pos)) return (arg_index != 0); return 0; } } /* todo */ static int fexpr_need_cdot_before_factor(const fexpr_t expr) { if (fexpr_is_integer(expr)) return 1; if (fexpr_is_builtin_symbol(expr, FEXPR_Infinity) || fexpr_is_builtin_symbol(expr, FEXPR_UnsignedInfinity)) return 1; if (fexpr_is_builtin_call(expr, FEXPR_Mul) && fexpr_nargs(expr) >= 1) { fexpr_t first; fexpr_view_arg(first, expr, 0); return fexpr_need_cdot_before_factor(first); } if (fexpr_is_builtin_call(expr, FEXPR_Neg) || fexpr_is_builtin_call(expr, FEXPR_Pos)) return 1; if (fexpr_is_builtin_call(expr, FEXPR_Pow) && fexpr_nargs(expr) == 2) { fexpr_t first; fexpr_view_arg(first, expr, 0); if (fexpr_is_integer(first)) return 1; } return 0; } void fexpr_write_latex_mul(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t arg; slong i, len; int need_parens; len = fexpr_nargs(expr); if (len == 0) { calcium_write(out, "(1)"); return; } fexpr_view_arg(arg, expr, 0); for (i = 0; i < len; i++) { /* 1 * x * y or -1 * x * y -> x * y, - x * y */ if (i == 0 && len >= 2 && fexpr_is_integer(arg) && (fexpr_equal_si(arg, 1) || fexpr_equal_si(arg, -1))) { if (fexpr_equal_si(arg, -1)) calcium_write(out, "-"); fexpr_view_next(arg); if (fexpr_need_cdot_before_factor(arg)) calcium_write(out, "1 \\cdot "); else calcium_write(out, " "); } else { need_parens = fexpr_need_parens_in_mul(arg, i); if (need_parens) calcium_write(out, "\\left("); fexpr_write_latex(out, arg, flags); if (need_parens) calcium_write(out, "\\right)"); if (i < len - 1) { fexpr_view_next(arg); if (fexpr_need_cdot_before_factor(arg)) calcium_write(out, " \\cdot "); else calcium_write(out, " "); } } } } static int fexpr_need_parens_in_numerator(const fexpr_t expr) { if (fexpr_is_atom(expr)) { return 0; } else { fexpr_t func; fexpr_view_func(func, expr); if (fexpr_is_builtin_symbol(func, FEXPR_Add)) return 1; if (fexpr_is_builtin_symbol(func, FEXPR_Sub)) return 1; return 0; } } static int fexpr_need_parens_in_denominator(const fexpr_t expr) { if (fexpr_is_atom(expr)) { return 0; } else { fexpr_t func; fexpr_view_func(func, expr); if (fexpr_is_builtin_symbol(func, FEXPR_Add)) return 1; if (fexpr_is_builtin_symbol(func, FEXPR_Sub)) return 1; if (fexpr_is_builtin_symbol(func, FEXPR_Mul)) return 1; if (fexpr_is_builtin_symbol(func, FEXPR_Div)) return 1; return 0; } } static int fexpr_can_extract_leading_sign(const fexpr_t expr) { if (fexpr_is_atom(expr)) { return fexpr_is_neg_integer(expr); } else { fexpr_t func; fexpr_view_func(func, expr); if (fexpr_is_builtin_symbol(func, FEXPR_Neg)) return 1; if (fexpr_is_builtin_symbol(func, FEXPR_Pos)) return 1; if (fexpr_is_builtin_symbol(func, FEXPR_Mul) && fexpr_nargs(expr) >= 1) { fexpr_view_next(func); return fexpr_can_extract_leading_sign(func); } return 0; } } void fexpr_write_latex_div(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t num, den; /* Expect exactly 2 arguments */ if (fexpr_nargs(expr) != 2) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_arg(num, expr, 0); fexpr_view_arg(den, expr, 1); if (flags & FEXPR_LATEX_SMALL) { int pnum, pden; pnum = fexpr_need_parens_in_numerator(num); pden = fexpr_need_parens_in_denominator(den); if (pnum) calcium_write(out, "\\left("); fexpr_write_latex(out, num, flags); if (pnum) calcium_write(out, "\\right)"); calcium_write(out, " / "); if (pden) calcium_write(out, "\\left("); fexpr_write_latex(out, den, flags); if (pden) calcium_write(out, "\\right)"); } else { if (fexpr_can_extract_leading_sign(num)) { char * s = fexpr_get_str_latex(num, flags); if (s[0] == '+' || s[0] == '-') { char tmp[2]; tmp[0] = s[0]; tmp[1] = '\0'; calcium_write(out, tmp); calcium_write(out, "\\frac{"); calcium_write(out, s + 1); calcium_write(out, "}{"); fexpr_write_latex(out, den, flags); calcium_write(out, "}"); } else { calcium_write(out, "\\frac{"); fexpr_write_latex(out, num, flags); calcium_write(out, "}{"); fexpr_write_latex(out, den, flags); calcium_write(out, "}"); } flint_free(s); } else { calcium_write(out, "\\frac{"); fexpr_write_latex(out, num, flags); calcium_write(out, "}{"); fexpr_write_latex(out, den, flags); calcium_write(out, "}"); } } } void fexpr_write_latex_neg_pos(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t arg; /* Expect exactly 1 argument */ if (fexpr_nargs(expr) != 1) { fexpr_write_latex_call(out, expr, flags); return; } if (fexpr_is_builtin_call(expr, FEXPR_Pos)) calcium_write(out, "+"); else calcium_write(out, "-"); fexpr_view_arg(arg, expr, 0); if (fexpr_is_builtin_call(arg, FEXPR_Neg) || fexpr_is_builtin_call(arg, FEXPR_Pos) || fexpr_is_builtin_call(arg, FEXPR_Add) || fexpr_is_builtin_call(arg, FEXPR_Sub) || fexpr_is_neg_integer(arg)) { calcium_write(out, "\\left("); fexpr_write_latex(out, arg, flags); calcium_write(out, "\\right)"); } else { fexpr_write_latex(out, arg, flags); } } static int fexpr_need_parens_in_add(const fexpr_t expr) { if (fexpr_is_atom(expr)) { return 0; } else { fexpr_t func; fexpr_view_func(func, expr); if (fexpr_is_builtin_symbol(func, FEXPR_Sub)) return 1; if (fexpr_is_builtin_symbol(func, FEXPR_Neg)) return 1; return 0; } } void fexpr_write_latex_add(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t arg; slong i, len; len = fexpr_nargs(expr); if (len == 0) { calcium_write(out, "(0)"); return; } fexpr_view_arg(arg, expr, 0); for (i = 0; i < len; i++) { if (i == 0) { fexpr_write_latex(out, arg, flags); } else { int need_parens = fexpr_need_parens_in_add(arg); if (need_parens) { calcium_write(out, " + \\left("); fexpr_write_latex(out, arg, flags); calcium_write(out, "\\right)"); } else { char * s = fexpr_get_str_latex(arg, flags); if (s[0] == '+' || s[0] == '-') { calcium_write(out, s); } else { calcium_write(out, " + "); calcium_write(out, s); } flint_free(s); } } fexpr_view_next(arg); } } static int fexpr_need_parens_in_sub(const fexpr_t expr) { if (fexpr_is_atom(expr)) { return fexpr_is_neg_integer(expr); } else { fexpr_t func; fexpr_view_func(func, expr); if (fexpr_is_builtin_symbol(func, FEXPR_Add)) return 1; if (fexpr_is_builtin_symbol(func, FEXPR_Sub)) return 1; if (fexpr_is_builtin_symbol(func, FEXPR_Neg)) return 1; if ((fexpr_is_builtin_symbol(func, FEXPR_Mul) || fexpr_is_builtin_symbol(func, FEXPR_Div)) && fexpr_nargs(expr) >= 1) { fexpr_t arg; fexpr_view_arg(arg, expr, 0); return fexpr_can_extract_leading_sign(arg); } return 0; } } void fexpr_write_latex_sub(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t arg; slong i, len; len = fexpr_nargs(expr); if (len == 0) { calcium_write(out, "(0)"); return; } fexpr_view_arg(arg, expr, 0); for (i = 0; i < len; i++) { if (i == 0) { fexpr_write_latex(out, arg, flags); } else { int need_parens = fexpr_need_parens_in_sub(arg); if (need_parens) { calcium_write(out, " - \\left("); fexpr_write_latex(out, arg, flags); calcium_write(out, "\\right)"); } else { calcium_write(out, " - "); fexpr_write_latex(out, arg, flags); } } fexpr_view_next(arg); } } static int fexpr_power_base_is_safe(const fexpr_t base) { if (fexpr_is_atom(base)) { if (fexpr_is_neg_integer(base)) return 0; return 1; } else { slong id; fexpr_t func; if (fexpr_is_any_builtin_call(base)) { fexpr_view_func(func, base); id = FEXPR_BUILTIN_ID(func->data[0]); if (id == FEXPR_Abs) return 1; if (id == FEXPR_Binomial) return 1; if (id == FEXPR_Matrix) return 1; if (id == FEXPR_Matrix2x2) return 1; if (id == FEXPR_Parentheses) return 1; if (id == FEXPR_Brackets) return 1; if (id == FEXPR_Braces) return 1; if (id == FEXPR_AngleBrackets) return 1; } return 0; } } void _fexpr_write_latex_pow(calcium_stream_t out, const fexpr_t base, const fexpr_t expo, ulong flags) { if (fexpr_is_any_builtin_call(base) && fexpr_nargs(base) == 1) { fexpr_t func, arg; fexpr_view_func(func, base); /* (f(x))^n written as f^n(x) for some standard functions */ switch (FEXPR_BUILTIN_ID(func->data[0])) { case FEXPR_Sin: case FEXPR_Cos: case FEXPR_Tan: case FEXPR_Cot: case FEXPR_Sec: case FEXPR_Csc: case FEXPR_Sinh: case FEXPR_Cosh: case FEXPR_Tanh: case FEXPR_Coth: case FEXPR_Sech: case FEXPR_Csch: case FEXPR_Log: case FEXPR_Sinc: case FEXPR_DedekindEta: fexpr_write_latex(out, func, flags); calcium_write(out, "^{"); fexpr_write_latex(out, expo, flags | FEXPR_LATEX_SMALL); fexpr_view_arg(arg, base, 0); calcium_write(out, "}\\!\\left("); fexpr_write_latex(out, arg, flags); calcium_write(out, "\\right)"); return; default: break; } } /* todo: generalize */ if ((fexpr_is_builtin_call(base, FEXPR_JacobiTheta) || fexpr_is_builtin_call(base, FEXPR_JacobiThetaQ)) && fexpr_nargs(base) == 3) { fexpr_t func, x, y, z; fexpr_view_func(func, base); fexpr_view_arg(x, base, 0); fexpr_view_arg(y, base, 1); fexpr_view_arg(z, base, 2); calcium_write(out, "\\theta_{"); fexpr_write_latex(out, x, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}^{"); fexpr_write_latex(out, expo, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}\\!\\left("); fexpr_write_latex(out, y, flags); calcium_write(out, ", "); fexpr_write_latex(out, z, flags); calcium_write(out, "\\right)"); return; } if (fexpr_is_symbol(base)) { slong underscore_pos; char * s; /* Need to change {x_3}^{y} -> x^{y}_{3} for correct rendering */ underscore_pos = _fexpr_is_symbol_with_internal_underscore(base); if (underscore_pos > 0) { char *sym, *sub; s = fexpr_get_symbol_str(base); s[underscore_pos] = '\0'; sym = s; sub = s + underscore_pos + 1; if (underscore_pos == 1) { calcium_write(out, sym); } else { calcium_write(out, "\\operatorname{"); calcium_write(out, sym); calcium_write(out, "}"); } calcium_write(out, "^{"); fexpr_write_latex(out, expo, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}_{"); calcium_write(out, sub); calcium_write(out, "}"); return; } } if (fexpr_is_any_builtin_call(base)) { slong id; fexpr_t func, x, y; fexpr_view_func(func, base); id = FEXPR_BUILTIN_ID(func->data[0]); if (fexpr_builtin_table[id].latex_writer == fexpr_write_latex_subscript && fexpr_nargs(base) == 1) { fexpr_view_arg(x, base, 0); fexpr_write_latex(out, func, flags); calcium_write(out, "_{"); fexpr_write_latex(out, x, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}^{"); fexpr_write_latex(out, expo, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); return; } if (fexpr_builtin_table[id].latex_writer == fexpr_write_latex_subscript_call && fexpr_nargs(base) == 2) { fexpr_view_arg(x, base, 0); fexpr_view_arg(y, base, 1); fexpr_write_latex(out, func, flags); calcium_write(out, "_{"); fexpr_write_latex(out, x, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}^{"); fexpr_write_latex(out, expo, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}\\!\\left("); fexpr_write_latex(out, y, flags); calcium_write(out, "\\right)"); return; } } if (fexpr_is_builtin_call(base, FEXPR_Subscript) && fexpr_nargs(base) == 2) { fexpr_t func, x; fexpr_view_arg(func, base, 0); fexpr_view_arg(x, base, 1); calcium_write(out, "{"); fexpr_write_latex(out, func, flags); calcium_write(out, "}_{"); fexpr_write_latex(out, x, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}^{"); fexpr_write_latex(out, expo, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); return; } if (fexpr_nargs(base) == 1) { fexpr_t func, x; int subscript; fexpr_view_func(func, base); if (_fexpr_is_symbol_with_trailing_underscore(func)) { fexpr_view_arg(x, base, 0); fexpr_write_latex_symbol(&subscript, out, func, flags); calcium_write(out, "_{"); fexpr_write_latex(out, x, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}^{"); fexpr_write_latex(out, expo, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); return; } } if (fexpr_power_base_is_safe(base)) { calcium_write(out, "{"); fexpr_write_latex(out, base, flags); calcium_write(out, "}^{"); fexpr_write_latex(out, expo, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); } else { calcium_write(out, "{\\left("); fexpr_write_latex(out, base, flags); calcium_write(out, "\\right)}^{"); fexpr_write_latex(out, expo, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); } } void fexpr_write_latex_pow(calcium_stream_t out, const fexpr_t expr, ulong flags) { if (fexpr_nargs(expr) == 2) { fexpr_t base, expo; fexpr_view_arg(base, expr, 0); fexpr_view_arg(expo, expr, 1); _fexpr_write_latex_pow(out, base, expo, flags); } else { fexpr_write_latex_call(out, expr, flags); } } static int fexpr_show_exp_as_power(const fexpr_t expr) { fexpr_t func, arg; slong i, nargs; if (fexpr_is_atom(expr)) return 1; fexpr_view_func(func, expr); /* todo: more systematic solution */ if (fexpr_is_builtin_symbol(func, FEXPR_Pos) || fexpr_is_builtin_symbol(func, FEXPR_Neg) || fexpr_is_builtin_symbol(func, FEXPR_Add) || fexpr_is_builtin_symbol(func, FEXPR_Sub) || fexpr_is_builtin_symbol(func, FEXPR_Mul) || fexpr_is_builtin_symbol(func, FEXPR_Div) || fexpr_is_builtin_symbol(func, FEXPR_Pow) || fexpr_is_builtin_symbol(func, FEXPR_Abs) || fexpr_is_builtin_symbol(func, FEXPR_RealAbs) || fexpr_is_builtin_symbol(func, FEXPR_Sqrt) || fexpr_is_builtin_symbol(func, FEXPR_Re) || fexpr_is_builtin_symbol(func, FEXPR_Im) || fexpr_is_builtin_symbol(func, FEXPR_Log)) { nargs = fexpr_nargs(expr); if (fexpr_is_builtin_symbol(func, FEXPR_Div) && nargs == 2) { fexpr_view_arg(arg, expr, 1); if (!fexpr_is_atom(arg)) return 0; } fexpr_view_arg(arg, expr, 0); for (i = 0; i < nargs; i++) { if (!fexpr_show_exp_as_power(arg)) return 0; fexpr_view_next(arg); } return 1; } return 0; } void fexpr_write_latex_exp(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t arg; slong nargs; nargs = fexpr_nargs(expr); if (nargs == 1) { fexpr_view_arg(arg, expr, 0); if (fexpr_show_exp_as_power(arg)) { calcium_write(out, "e^{"); fexpr_write_latex(out, arg, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); } else { calcium_write(out, "\\exp\\!\\left("); fexpr_write_latex(out, arg, flags); calcium_write(out, "\\right)"); } return; } fexpr_write_latex_call(out, expr, flags); } void fexpr_write_latex_factorial(calcium_stream_t out, const fexpr_t expr, ulong flags) { if (fexpr_nargs(expr) == 1) { fexpr_t func, arg; fexpr_view_func(func, expr); fexpr_view_arg(arg, expr, 0); if (fexpr_is_symbol(arg) || (fexpr_is_integer(arg) && !fexpr_is_neg_integer(arg))) { fexpr_write_latex(out, arg, flags); } else { calcium_write(out, "\\left("); fexpr_write_latex(out, arg, flags); calcium_write(out, "\\right)"); } if (fexpr_is_builtin_symbol(func, FEXPR_DoubleFactorial)) calcium_write(out, "!!"); else calcium_write(out, "!"); } else { fexpr_write_latex_call(out, expr, flags); } } void fexpr_write_latex_sum_product(calcium_stream_t out, const fexpr_t expr, ulong flags) { slong nargs, forexpr_nargs; fexpr_t f, forexpr, var, low, high, domain, predicate; int have_predicate = 0; int have_domain = 0; int have_low_high = 0; int need_parens; nargs = fexpr_nargs(expr); if (nargs != 2 && nargs != 3) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_arg(f, expr, 0); fexpr_view_arg(forexpr, expr, 1); if (nargs == 3) { fexpr_view_arg(predicate, expr, 2); have_predicate = 1; } forexpr_nargs = fexpr_nargs(forexpr); if (forexpr_nargs != 2 && forexpr_nargs != 3) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_arg(var, forexpr, 0); if (forexpr_nargs == 2) { fexpr_view_arg(domain, forexpr, 1); have_domain = 1; } else { fexpr_view_arg(low, forexpr, 1); fexpr_view_arg(high, forexpr, 2); have_low_high = 1; } if (fexpr_is_builtin_call(expr, FEXPR_Sum)) calcium_write(out, "\\sum"); else calcium_write(out, "\\prod"); if (have_domain) { if (have_predicate) { calcium_write(out, "_{\\textstyle{"); fexpr_write_latex(out, var, flags); calcium_write(out, " \\in "); fexpr_write_latex(out, domain, flags); calcium_write(out, " \\atop "); fexpr_write_latex(out, predicate, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}}"); } else { calcium_write(out, "_{"); fexpr_write_latex(out, var, flags); calcium_write(out, " \\in "); fexpr_write_latex(out, domain, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); } } else if (have_low_high) { if (have_predicate) { calcium_write(out, "_{\\textstyle{"); fexpr_write_latex(out, var, flags); calcium_write(out, "="); fexpr_write_latex(out, low, flags | FEXPR_LATEX_SMALL); calcium_write(out, " \\atop "); fexpr_write_latex(out, predicate, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}}^{"); fexpr_write_latex(out, high, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); } else { calcium_write(out, "_{"); fexpr_write_latex(out, var, flags); calcium_write(out, "="); fexpr_write_latex(out, low, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}^{"); fexpr_write_latex(out, high, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); } } calcium_write(out, " "); need_parens = fexpr_is_builtin_call(f, FEXPR_Add) || fexpr_is_builtin_call(f, FEXPR_Sub); if (need_parens) calcium_write(out, "\\left("); fexpr_write_latex(out, f, flags); if (need_parens) calcium_write(out, "\\right)"); } void fexpr_write_latex_divsum(calcium_stream_t out, const fexpr_t expr, ulong flags) { slong nargs, forexpr_nargs; fexpr_t f, forexpr, var, high, predicate; slong expected_forargs; int have_predicate = 0; int need_parens; nargs = fexpr_nargs(expr); if (nargs != 2 && nargs != 3) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_arg(f, expr, 0); fexpr_view_arg(forexpr, expr, 1); if (nargs == 3) { fexpr_view_arg(predicate, expr, 2); have_predicate = 1; } forexpr_nargs = fexpr_nargs(forexpr); if (fexpr_is_builtin_call(expr, FEXPR_DivisorSum) || fexpr_is_builtin_call(expr, FEXPR_DivisorProduct)) expected_forargs = 2; else expected_forargs = 1; if (forexpr_nargs != expected_forargs) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_arg(var, forexpr, 0); if (forexpr_nargs == 2) fexpr_view_arg(high, forexpr, 1); if (fexpr_is_builtin_call(expr, FEXPR_DivisorSum) || fexpr_is_builtin_call(expr, FEXPR_PrimeSum)) calcium_write(out, "\\sum_{"); else calcium_write(out, "\\prod_{"); if (fexpr_is_builtin_call(expr, FEXPR_DivisorSum) || fexpr_is_builtin_call(expr, FEXPR_DivisorProduct)) { fexpr_write_latex(out, var, flags | FEXPR_LATEX_SMALL); calcium_write(out, " \\mid "); fexpr_write_latex(out, high, flags | FEXPR_LATEX_SMALL); if (have_predicate) { calcium_write(out, ",\\, "); fexpr_write_latex(out, predicate, flags | FEXPR_LATEX_SMALL); } } else { if (have_predicate) fexpr_write_latex(out, predicate, flags | FEXPR_LATEX_SMALL); else fexpr_write_latex(out, var, flags | FEXPR_LATEX_SMALL); } calcium_write(out, "} "); need_parens = fexpr_is_builtin_call(f, FEXPR_Add) || fexpr_is_builtin_call(f, FEXPR_Sub); if (need_parens) calcium_write(out, "\\left("); fexpr_write_latex(out, f, flags); if (need_parens) calcium_write(out, "\\right)"); } void fexpr_write_latex_integral(calcium_stream_t out, const fexpr_t expr, ulong flags) { if (fexpr_nargs(expr) == 2) { fexpr_t f, iter, var, low, high, domain; int need_parens; fexpr_view_arg(f, expr, 0); fexpr_view_arg(iter, expr, 1); need_parens = fexpr_is_builtin_call(f, FEXPR_Add) || fexpr_is_builtin_call(f, FEXPR_Sub); if (fexpr_is_builtin_call(iter, FEXPR_For)) { if (fexpr_nargs(iter) == 2) { fexpr_view_arg(var, iter, 0); fexpr_view_arg(domain, iter, 1); calcium_write(out, "\\int_{"); fexpr_write_latex(out, var, flags | FEXPR_LATEX_SMALL); calcium_write(out, " \\in "); fexpr_write_latex(out, domain, flags | FEXPR_LATEX_SMALL); calcium_write(out, "} "); if (need_parens) calcium_write(out, "\\left("); fexpr_write_latex(out, f, flags); if (need_parens) calcium_write(out, "\\right)"); calcium_write(out, " \\, d"); fexpr_write_latex(out, var, flags); return; } if (fexpr_nargs(iter) == 3) { fexpr_view_arg(var, iter, 0); fexpr_view_arg(low, iter, 1); fexpr_view_arg(high, iter, 2); calcium_write(out, "\\int_{"); fexpr_write_latex(out, low, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}^{"); fexpr_write_latex(out, high, flags | FEXPR_LATEX_SMALL); calcium_write(out, "} "); if (need_parens) calcium_write(out, "\\left("); fexpr_write_latex(out, f, flags); if (need_parens) calcium_write(out, "\\right)"); calcium_write(out, " \\, d"); fexpr_write_latex(out, var, flags); return; } } } fexpr_write_latex_call(out, expr, flags); } void fexpr_write_latex_limit(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t op, formula, forexpr, var, point, predicate; slong nargs, id; int have_predicate = 0; int parens; nargs = fexpr_nargs(expr); if (nargs != 2 && nargs != 3) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_func(op, expr); fexpr_view_arg(formula, expr, 0); fexpr_view_arg(forexpr, expr, 1); if (fexpr_nargs(forexpr) != 2) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_arg(var, forexpr, 0); fexpr_view_arg(point, forexpr, 1); if (nargs == 3) { fexpr_view_arg(predicate, expr, 2); have_predicate = 1; } id = FEXPR_BUILTIN_ID(op->data[0]); if (id == FEXPR_SequenceLimitInferior) calcium_write(out, "\\liminf_{"); else if (id == FEXPR_SequenceLimitSuperior) calcium_write(out, "\\limsup_{"); else calcium_write(out, "\\lim_{"); fexpr_write_latex(out, var, flags); calcium_write(out, " \\to "); if (id == FEXPR_LeftLimit || id == FEXPR_RightLimit) calcium_write(out, "{"); fexpr_write_latex(out, point, flags | FEXPR_LATEX_SMALL); if (id == FEXPR_LeftLimit) calcium_write(out, "}^{-}"); if (id == FEXPR_RightLimit) calcium_write(out, "}^{+}"); if (have_predicate) { calcium_write(out, ",\\,"); fexpr_write_latex(out, predicate, flags | FEXPR_LATEX_SMALL); } calcium_write(out, "} "); parens = (fexpr_is_builtin_call(formula, FEXPR_Add) || fexpr_is_builtin_call(formula, FEXPR_Sub)); if (parens) calcium_write(out, "\\left["); fexpr_write_latex(out, formula, flags); if (parens) calcium_write(out, "\\right]"); } void fexpr_write_latex_residue(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t op, formula, forexpr, var, point; slong nargs, id; int parens; nargs = fexpr_nargs(expr); if (nargs != 2) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_func(op, expr); fexpr_view_arg(formula, expr, 0); fexpr_view_arg(forexpr, expr, 1); if (fexpr_nargs(forexpr) != 2) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_arg(var, forexpr, 0); fexpr_view_arg(point, forexpr, 1); id = FEXPR_BUILTIN_ID(op->data[0]); if (id == FEXPR_ComplexZeroMultiplicity) calcium_write(out, "\\mathop{\\operatorname{ord}}\\limits_{"); else calcium_write(out, "\\mathop{\\operatorname{res}}\\limits_{"); fexpr_write_latex(out, var, flags); calcium_write(out, "="); fexpr_write_latex(out, point, flags); calcium_write(out, "} "); parens = (fexpr_is_builtin_call(formula, FEXPR_Add) || fexpr_is_builtin_call(formula, FEXPR_Sub)); if (parens) calcium_write(out, "\\left["); fexpr_write_latex(out, formula, flags); if (parens) calcium_write(out, "\\right]"); } void _fexpr_write_latex_derivative(calcium_stream_t out, const fexpr_t f, const fexpr_t subscript, const fexpr_t order, ulong flags) { if (fexpr_equal_ui(order, 1)) { fexpr_write_latex(out, f, flags); calcium_write(out, "'"); } else if (fexpr_equal_ui(order, 2)) { fexpr_write_latex(out, f, flags); calcium_write(out, "''"); } else if (fexpr_equal_ui(order, 3)) { fexpr_write_latex(out, f, flags); calcium_write(out, "'''"); } else { calcium_write(out, "{"); fexpr_write_latex(out, f, flags); calcium_write(out, "}^{("); fexpr_write_latex(out, order, flags); calcium_write(out, ")}"); } if (subscript != NULL) { calcium_write(out, "_{"); fexpr_write_latex(out, subscript, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); } } void fexpr_write_latex_derivative(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t formula, forexpr, var, point, order; slong nargs, forexpr_nargs; int parens; ulong tmp; nargs = fexpr_nargs(expr); if (nargs != 2) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_arg(formula, expr, 0); fexpr_view_arg(forexpr, expr, 1); forexpr_nargs = fexpr_nargs(forexpr); if (forexpr_nargs != 2 && forexpr_nargs != 3) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_arg(var, forexpr, 0); fexpr_view_arg(point, forexpr, 1); if (forexpr_nargs == 3) { fexpr_view_arg(order, forexpr, 2); } else { order->data = &tmp; order->alloc = 1; fexpr_set_ui(order, 1); } /* d/dx f(x) -> f'(x) */ if (fexpr_nargs(formula) == 1) { fexpr_t f, x; fexpr_view_func(f, formula); fexpr_view_arg(x, formula, 0); if (fexpr_equal(x, var) && fexpr_is_symbol(f) && !fexpr_is_builtin_symbol(f, FEXPR_Exp) && !fexpr_is_builtin_symbol(f, FEXPR_Sqrt)) { _fexpr_write_latex_derivative(out, f, NULL, order, flags); calcium_write(out, "\\!\\left("); fexpr_write_latex(out, point, flags); calcium_write(out, "\\right)"); return; } } /* d/dx f_n(x) -> f'_n(x) */ if (fexpr_nargs(formula) == 2) { fexpr_t f, n, x; slong id; fexpr_view_func(f, formula); fexpr_view_arg(n, formula, 0); fexpr_view_arg(x, formula, 1); if (fexpr_equal(x, var) && fexpr_is_any_builtin_symbol(f)) { id = FEXPR_BUILTIN_ID(f->data[0]); if (fexpr_builtin_table[id].latex_writer == fexpr_write_latex_subscript_call) { _fexpr_write_latex_derivative(out, f, n, order, flags); calcium_write(out, "\\!\\left("); fexpr_write_latex(out, point, flags); calcium_write(out, "\\right)"); return; } } } if (!fexpr_equal(var, point)) calcium_write(out, "\\left["); if (fexpr_equal_ui(order, 1)) { calcium_write(out, "\\frac{d}{d "); fexpr_write_latex(out, var, flags); calcium_write(out, "}\\, "); } else { calcium_write(out, "\\frac{d^{"); fexpr_write_latex(out, order, flags); calcium_write(out, "}}{{d "); fexpr_write_latex(out, var, flags); calcium_write(out, "}^{"); fexpr_write_latex(out, order, flags); calcium_write(out, "}}\\, "); } parens = (fexpr_is_builtin_call(formula, FEXPR_Add) || fexpr_is_builtin_call(formula, FEXPR_Sub)); if (parens) calcium_write(out, "\\left["); fexpr_write_latex(out, formula, flags); if (parens) calcium_write(out, "\\right]"); if (!fexpr_equal(var, point)) { calcium_write(out, " \\right]_{"); fexpr_write_latex(out, var, flags); calcium_write(out, " = "); fexpr_write_latex(out, point, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); } } void fexpr_write_latex_setop(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t op, formula, forexpr, var, domain, predicate; const char * ops; slong nargs, id; int have_predicate = 0, have_domain = 0; int parens; nargs = fexpr_nargs(expr); fexpr_view_func(op, expr); id = FEXPR_BUILTIN_ID(op->data[0]); switch (id) { case FEXPR_Minimum: ops = "\\min"; break; case FEXPR_Maximum: ops = "\\max"; break; case FEXPR_ArgMin: ops = "\\operatorname{arg\\,min}"; break; case FEXPR_ArgMax: ops = "\\operatorname{arg\\,max}"; break; case FEXPR_ArgMinUnique: ops = "\\operatorname{arg\\,min*}"; break; case FEXPR_ArgMaxUnique: ops = "\\operatorname{arg\\,max*}"; break; case FEXPR_Infimum: ops = "\\operatorname{inf}"; break; case FEXPR_Supremum: ops = "\\operatorname{sup}"; break; case FEXPR_Zeros: ops = "\\operatorname{zeros}"; break; case FEXPR_UniqueZero: ops = "\\operatorname{zero*}"; break; case FEXPR_Solutions: ops = "\\operatorname{solutions}"; break; case FEXPR_UniqueSolution: ops = "\\operatorname{solution*}"; break; case FEXPR_Poles: ops = "\\operatorname{poles}"; break; default: ops = ""; } if (nargs == 1) { fexpr_t arg; fexpr_view_arg(arg, expr, 0); calcium_write(out, ops); if (fexpr_is_builtin_call(arg, FEXPR_Set)) { calcium_write(out, " "); fexpr_write_latex(out, arg, flags); } else { calcium_write(out, "\\left("); fexpr_write_latex(out, arg, flags); calcium_write(out, "\\right)"); } return; } if (nargs != 2 && nargs != 3) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_arg(formula, expr, 0); fexpr_view_arg(forexpr, expr, 1); if (fexpr_nargs(forexpr) != 1 && fexpr_nargs(forexpr) != 2) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_arg(var, forexpr, 0); if (fexpr_nargs(forexpr) == 1) { have_domain = 0; } else { fexpr_view_arg(domain, forexpr, 1); have_domain = 1; } if (nargs == 3) { fexpr_view_arg(predicate, expr, 2); have_predicate = 1; } calcium_write(out, "\\mathop{"); calcium_write(out, ops); calcium_write(out, "\\,}\\limits_{"); if (have_domain) { fexpr_write_latex(out, var, flags | FEXPR_LATEX_SMALL); calcium_write(out, " \\in "); fexpr_write_latex(out, domain, flags | FEXPR_LATEX_SMALL); } if (have_predicate) { if (have_domain) calcium_write(out, ",\\,"); fexpr_write_latex(out, predicate, flags | FEXPR_LATEX_SMALL); } calcium_write(out, "} "); parens = (fexpr_is_builtin_call(formula, FEXPR_Add) || fexpr_is_builtin_call(formula, FEXPR_Sub) || fexpr_is_builtin_call(formula, FEXPR_Neg) || fexpr_is_builtin_call(formula, FEXPR_Sum) || fexpr_is_builtin_call(formula, FEXPR_Product) || fexpr_is_builtin_call(formula, FEXPR_Integral)); if (parens) calcium_write(out, "\\left["); fexpr_write_latex(out, formula, flags); if (parens) calcium_write(out, "\\right]"); } void fexpr_write_latex_logic(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t arg; slong i, nargs; nargs = fexpr_nargs(expr); if (fexpr_is_builtin_call(expr, FEXPR_Not) && nargs == 1) { fexpr_view_arg(arg, expr, 0); if (flags & FEXPR_LATEX_LOGIC) calcium_write(out, "\\neg "); else calcium_write(out, "\\operatorname{not} "); if (fexpr_is_atom(arg)) { fexpr_write_latex(out, arg, flags); } else { if (!(flags & FEXPR_LATEX_LOGIC)) calcium_write(out, "\\,"); calcium_write(out, "\\left("); fexpr_write_latex(out, arg, flags); calcium_write(out, "\\right)"); } return; } if (fexpr_is_builtin_call(expr, FEXPR_Or) && nargs >= 1) { fexpr_view_arg(arg, expr, 0); for (i = 0; i < nargs; i++) { if (fexpr_is_builtin_call(arg, FEXPR_And) || fexpr_is_builtin_call(arg, FEXPR_Or) || fexpr_is_builtin_call(arg, FEXPR_Not)) { calcium_write(out, "\\left("); fexpr_write_latex(out, arg, flags); calcium_write(out, "\\right)"); } else { fexpr_write_latex(out, arg, flags); } if (i < nargs - 1) { if (flags & FEXPR_LATEX_LOGIC) calcium_write(out, " \\,\\lor\\, "); else calcium_write(out, " \\;\\mathbin{\\operatorname{or}}\\; "); fexpr_view_next(arg); } } return; } if (fexpr_is_builtin_call(expr, FEXPR_And) && nargs >= 1) { fexpr_view_arg(arg, expr, 0); for (i = 0; i < nargs; i++) { if (fexpr_is_builtin_call(arg, FEXPR_And) || fexpr_is_builtin_call(arg, FEXPR_Or) || fexpr_is_builtin_call(arg, FEXPR_All) || fexpr_is_builtin_call(arg, FEXPR_Exists)) { calcium_write(out, "\\left("); fexpr_write_latex(out, arg, flags); calcium_write(out, "\\right)"); } else { fexpr_write_latex(out, arg, flags); } if (i < nargs - 1) { if (flags & FEXPR_LATEX_LOGIC) calcium_write(out, " \\,\\land\\, "); else if (flags & FEXPR_LATEX_SMALL) /* see see ff190c */ calcium_write(out, " ,\\, "); else calcium_write(out, " \\;\\mathbin{\\operatorname{and}}\\; "); fexpr_view_next(arg); } } return; } if (fexpr_is_builtin_call(expr, FEXPR_Implies) && nargs == 2) { fexpr_t arg1, arg2; fexpr_view_arg(arg1, expr, 0); fexpr_view_arg(arg2, expr, 1); if (!(fexpr_is_atom(arg1) || fexpr_is_builtin_call(arg1, FEXPR_Element))) { calcium_write(out, "\\left("); fexpr_write_latex(out, arg1, flags); calcium_write(out, "\\right)"); } else { fexpr_write_latex(out, arg1, flags); } calcium_write(out, " \\;\\implies\\; "); if (!(fexpr_is_atom(arg2) || fexpr_is_builtin_call(arg2, FEXPR_Element))) { calcium_write(out, "\\left("); fexpr_write_latex(out, arg2, flags); calcium_write(out, "\\right)"); } else { fexpr_write_latex(out, arg2, flags); } return; } if (fexpr_is_builtin_call(expr, FEXPR_Equivalent) && nargs >= 1) { fexpr_view_func(arg, expr); for (i = 0; i < nargs; i++) { fexpr_view_next(arg); if (!fexpr_is_atom(arg)) calcium_write(out, "\\left("); fexpr_write_latex(out, arg, flags); if (!fexpr_is_atom(arg)) calcium_write(out, "\\right)"); if (i < nargs - 1) { calcium_write(out, " \\iff "); } } return; } if ((fexpr_is_builtin_call(expr, FEXPR_All) || fexpr_is_builtin_call(expr, FEXPR_Exists)) && (nargs == 2 || nargs == 3)) { fexpr_t func, forarg, var, domain, condition; fexpr_view_arg(func, expr, 0); fexpr_view_arg(forarg, expr, 1); if (nargs == 3) fexpr_view_arg(condition, expr, 2); if (fexpr_nargs(forarg) == 1 || fexpr_nargs(forarg) == 2) { int have_domain = (fexpr_nargs(forarg) == 2); fexpr_view_arg(var, forarg, 0); if (have_domain) fexpr_view_arg(domain, forarg, 1); if (flags & FEXPR_LATEX_LOGIC) { if (fexpr_is_builtin_call(expr, FEXPR_All)) calcium_write(out, "\\forall "); else calcium_write(out, "\\exists "); fexpr_write_latex(out, var, flags); if (have_domain) { calcium_write(out, " \\in "); fexpr_write_latex(out, domain, flags); } if (nargs == 3) { calcium_write(out, ", \\,"); fexpr_write_latex(out, condition, flags); } calcium_write(out, " : \\, "); fexpr_write_latex(out, func, flags); } else { fexpr_write_latex(out, func, flags); if (fexpr_is_builtin_call(expr, FEXPR_All)) calcium_write(out, " \\;\\text{ for all } "); else calcium_write(out, " \\;\\text{ for some } "); fexpr_write_latex(out, var, flags); if (have_domain) { calcium_write(out, " \\in "); fexpr_write_latex(out, domain, flags); } if (nargs == 3) { calcium_write(out, " \\text{ with } "); fexpr_write_latex(out, condition, flags); } } return; } } if (fexpr_is_builtin_call(expr, FEXPR_Logic) && nargs == 1) { fexpr_t arg; fexpr_view_arg(arg, expr, 0); fexpr_write_latex(out, arg, flags | FEXPR_LATEX_LOGIC); return; } /* todo: move this */ if (fexpr_is_builtin_call(expr, FEXPR_CongruentMod) && nargs == 3) { fexpr_t arg; fexpr_view_arg(arg, expr, 0); fexpr_write_latex(out, arg, flags); calcium_write(out, " \\equiv "); fexpr_view_next(arg); fexpr_write_latex(out, arg, flags); calcium_write(out, " \\pmod {"); fexpr_view_next(arg); fexpr_write_latex(out, arg, flags); calcium_write(out, " }"); return; } fexpr_write_latex_call(out, expr, flags); } void fexpr_write_latex_cases(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t arg, value, condition; slong i, nargs; calcium_write(out, "\\begin{cases} "); nargs = fexpr_nargs(expr); fexpr_view_arg(arg, expr, 0); for (i = 0; i < nargs; i++) { if (fexpr_nargs(arg) != 2) continue; fexpr_view_arg(value, arg, 0); fexpr_view_arg(condition, arg, 1); fexpr_write_latex(out, value, flags /* | FEXPR_LATEX_SMALL */); calcium_write(out, ", & "); if (fexpr_is_builtin_symbol(condition, FEXPR_Otherwise)) calcium_write(out, "\\text{otherwise}"); else fexpr_write_latex(out, condition, flags /* | FEXPR_LATEX_SMALL */); calcium_write(out, "\\\\"); if (i < nargs - 1) fexpr_view_next(arg); } calcium_write(out, " \\end{cases}"); } void fexpr_write_latex_simple(calcium_stream_t out, const fexpr_t expr, ulong flags) { slong i; const char * a; const char * b; fexpr_t func, arg; if (fexpr_nargs(expr) != 1 || !fexpr_is_any_builtin_call(expr)) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_func(func, expr); fexpr_view_arg(arg, expr, 0); i = FEXPR_BUILTIN_ID(func->data[0]); switch (i) { case FEXPR_Sqrt: a = "\\sqrt{"; b = "}"; break; case FEXPR_Conjugate: a = "\\overline{"; b = "}"; break; case FEXPR_Cardinality: case FEXPR_Length: a = "\\# "; b = ""; break; case FEXPR_Abs: case FEXPR_RealAbs: a = "\\left|"; b = "\\right|"; break; case FEXPR_Floor: a = "\\left\\lfloor "; b = " \\right\\rfloor"; break; case FEXPR_Ceil: a = "\\left\\lceil "; b = "\\right\\rceil"; break; case FEXPR_Parentheses: a = "\\left("; b = "\\right)"; break; case FEXPR_Brackets: a = "\\left["; b = "\\right]"; break; case FEXPR_Braces: a = "\\left\\{"; b = "\\right\\}"; break; case FEXPR_AngleBrackets: a = "\\left\\langle "; b = "\\right\\rangle"; break; case FEXPR_IsEven: a = ""; b = " \\text{ even}"; break; case FEXPR_IsOdd: a = ""; b = " \\text{ odd}"; break; case FEXPR_IsPrime: a = ""; b = " \\text{ prime}"; break; case FEXPR_Enclosure: a = "\\left(\\in "; b = " \\right)"; break; case FEXPR_Guess: a = "\\left(?\\; "; b = " \\right)"; break; case FEXPR_Approximation: a = "\\left(\\approx "; b = " \\right)"; break; default: fexpr_write_latex_call(out, expr, flags); return; } calcium_write(out, a); fexpr_write_latex(out, arg, flags); calcium_write(out, b); } void _fexpr_write_latex_simple2(calcium_stream_t out, const fexpr_t expr, ulong flags) { slong i; const char * a; const char * b; const char * c; fexpr_t func, arg1, arg2; if (fexpr_nargs(expr) != 2 || !fexpr_is_any_builtin_call(expr)) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_func(func, expr); fexpr_view_arg(arg1, expr, 0); fexpr_view_arg(arg2, expr, 1); i = FEXPR_BUILTIN_ID(func->data[0]); switch (i) { case FEXPR_RisingFactorial: a = "\\left("; b = "\\right)_{"; c = "}"; break; case FEXPR_FallingFactorial: a = "\\left("; b = "\\right)^{\\underline{"; c = "}}"; break; case FEXPR_Binomial: a = "{"; b = " \\choose "; c = "}"; break; case FEXPR_StirlingCycle: a = "\\left[{"; b = " \\atop "; c = "}\\right]"; break; case FEXPR_StirlingS1: a = "s\\!\\left("; b = ", "; c = "\\right)"; break; case FEXPR_StirlingS2: a = "\\left\\{{"; b = " \\atop "; c = "}\\right\\}"; break; case FEXPR_LegendreSymbol: case FEXPR_JacobiSymbol: case FEXPR_KroneckerSymbol: a = "\\left(\\frac{"; b = "}{"; c = "}\\right)"; break; case FEXPR_Interval: a = "\\left["; b = ", "; c = "\\right]"; break; case FEXPR_OpenInterval: a = "\\left("; b = ", "; c = "\\right)"; break; case FEXPR_ClosedOpenInterval: a = "\\left["; b = ", "; c = "\\right)"; break; case FEXPR_OpenClosedInterval: a = "\\left("; b = ", "; c = "\\right]"; break; case FEXPR_RealBall: a = "\\left["; b = " \\pm "; c = "\\right]"; break; case FEXPR_OpenRealBall: a = "\\left("; b = " \\pm "; c = "\\right)"; break; case FEXPR_KroneckerDelta: a = "\\delta_{("; b = ","; c = ")}"; break; case FEXPR_Subscript: case FEXPR_Item: a = "{"; b = "}_{"; c = "}"; break; default: fexpr_write_latex_call(out, expr, flags); return; } calcium_write(out, a); fexpr_write_latex(out, arg1, flags); calcium_write(out, b); fexpr_write_latex(out, arg2, flags); calcium_write(out, c); } void fexpr_write_latex_simple2(calcium_stream_t out, const fexpr_t expr, ulong flags) { _fexpr_write_latex_simple2(out, expr, flags); } void fexpr_write_latex_simple2_small(calcium_stream_t out, const fexpr_t expr, ulong flags) { _fexpr_write_latex_simple2(out, expr, flags | FEXPR_LATEX_SMALL); } void fexpr_write_latex_collection(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t arg; slong nargs; nargs = fexpr_nargs(expr); /* Set comprehension */ if (fexpr_is_builtin_call(expr, FEXPR_Set) && (nargs == 2 || nargs == 3)) { slong for_nargs; fexpr_view_arg(arg, expr, 1); for_nargs = fexpr_nargs(arg); if (fexpr_is_builtin_call(arg, FEXPR_For) && (for_nargs == 2 || for_nargs == 1)) { fexpr_t func, var, domain, predicate; fexpr_view_arg(func, expr, 0); fexpr_view_arg(var, arg, 0); if (for_nargs == 2) fexpr_view_arg(domain, arg, 1); calcium_write(out, "\\left\\{ "); fexpr_write_latex(out, func, flags); if (for_nargs == 2 || nargs == 3) calcium_write(out, " : "); if (for_nargs == 2) { fexpr_write_latex(out, var, flags); calcium_write(out, " \\in "); fexpr_write_latex(out, domain, flags); } if (nargs == 3) { fexpr_view_arg(predicate, expr, 2); if (for_nargs == 2) calcium_write(out, "\\,\\mathbin{\\operatorname{and}}\\, "); fexpr_write_latex(out, predicate, flags); } calcium_write(out, " \\right\\}"); return; } } if (fexpr_is_builtin_call(expr, FEXPR_Set)) calcium_write(out, "\\left\\{"); else if (fexpr_is_builtin_call(expr, FEXPR_Tuple)) calcium_write(out, "\\left("); else if (fexpr_is_builtin_call(expr, FEXPR_List)) calcium_write(out, "\\left["); else if (fexpr_is_builtin_call(expr, FEXPR_Lattice)) calcium_write(out, "\\Lambda_{("); { fexpr_t func, var, a, b; slong for_nargs; if (nargs == 2) { fexpr_view_arg(arg, expr, 1); for_nargs = fexpr_nargs(arg); } /* {f(n) for n=a..b} -- todo: special cases for infinity, explicit integer a and b */ if (nargs == 2 && fexpr_is_builtin_call(arg, FEXPR_For) && for_nargs == 3) { fexpr_t first, second, last, t, a1; fmpz_t n; fexpr_view_arg(func, expr, 0); fexpr_view_arg(var, arg, 0); fexpr_view_arg(a, arg, 1); fexpr_view_arg(b, arg, 2); fexpr_init(first); fexpr_init(second); fexpr_init(last); fexpr_init(a1); fexpr_init(t); fmpz_init(n); if (fexpr_is_integer(a)) { fexpr_get_fmpz(n, a); fmpz_add_ui(n, n, 1); fexpr_set_fmpz(a1, n); } else { fexpr_set_ui(t, 1); fexpr_add(a1, a, t); } fexpr_replace(first, func, var, a); fexpr_replace(second, func, var, a1); fexpr_replace(last, func, var, b); fexpr_write_latex(out, first, flags); calcium_write(out, ", "); fexpr_write_latex(out, second, flags); calcium_write(out, ", \\ldots, "); fexpr_write_latex(out, last, flags); fexpr_clear(first); fexpr_clear(second); fexpr_clear(last); fexpr_clear(a1); fexpr_clear(t); fmpz_clear(n); } else if (nargs >= 1) { slong i; fexpr_view_arg(arg, expr, 0); for (i = 0; i < nargs; i++) { fexpr_write_latex(out, arg, flags); if (i < nargs - 1) { calcium_write(out, ", "); fexpr_view_next(arg); } } } } if (fexpr_is_builtin_call(expr, FEXPR_Set)) calcium_write(out, "\\right\\}"); else if (fexpr_is_builtin_call(expr, FEXPR_Tuple)) calcium_write(out, "\\right)"); else if (fexpr_is_builtin_call(expr, FEXPR_List)) calcium_write(out, "\\right]"); else if (fexpr_is_builtin_call(expr, FEXPR_Lattice)) calcium_write(out, ")}"); } void fexpr_write_latex_range(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t a, b; if (fexpr_is_builtin_call(expr, FEXPR_IntegersGreaterEqual) && fexpr_nargs(expr) == 1) { fexpr_view_arg(a, expr, 0); calcium_write(out, "\\mathbb{Z}_{\\ge "); fexpr_write_latex(out, a, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); return; } if (fexpr_is_builtin_call(expr, FEXPR_IntegersLessEqual) && fexpr_nargs(expr) == 1) { fexpr_view_arg(a, expr, 0); if (fexpr_is_integer(a)) { fmpz_t n; fmpz_init(n); fexpr_get_fmpz(n, a); calcium_write(out, "\\{"); calcium_write_fmpz(out, n); calcium_write(out, ", "); fmpz_sub_ui(n, n, 1); calcium_write_fmpz(out, n); calcium_write(out, ", \\ldots\\}"); fmpz_clear(n); } else { calcium_write(out, "\\mathbb{Z}_{\\le "); fexpr_write_latex(out, a, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); } return; } if (fexpr_is_builtin_call(expr, FEXPR_Range) && fexpr_nargs(expr) == 2) { fexpr_view_arg(a, expr, 0); fexpr_view_arg(b, expr, 1); if (fexpr_is_integer(a)) { fmpz_t n; fmpz_init(n); fexpr_get_fmpz(n, a); calcium_write(out, "\\{"); calcium_write_fmpz(out, n); calcium_write(out, ", "); fmpz_add_ui(n, n, 1); calcium_write_fmpz(out, n); calcium_write(out, ", \\ldots, "); fexpr_write_latex(out, b, flags); calcium_write(out, "\\}"); fmpz_clear(n); } else { calcium_write(out, "\\{"); fexpr_write_latex(out, a, flags); calcium_write(out, ", "); fexpr_write_latex(out, a, flags); calcium_write(out, " + 1, \\ldots, "); fexpr_write_latex(out, b, flags); calcium_write(out, "\\}"); } return; } fexpr_write_latex_call(out, expr, flags); } void fexpr_write_latex_matrix(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t arg, row, elem; slong i, j, nargs, nrows, ncols; nargs = fexpr_nargs(expr); if (fexpr_is_builtin_call(expr, FEXPR_RowMatrix) || fexpr_is_builtin_call(expr, FEXPR_ColumnMatrix)) { int isrow = fexpr_is_builtin_call(expr, FEXPR_RowMatrix); calcium_write(out, "\\displaystyle{\\begin{pmatrix}"); if (nargs > 0) { fexpr_view_arg(elem, expr, 0); for (i = 0; i < nargs; i++) { fexpr_write_latex(out, elem, flags); if (i < nargs - 1) { if (isrow) calcium_write(out, " & "); else calcium_write(out, " \\\\ "); fexpr_view_next(elem); } } } calcium_write(out, "\\end{pmatrix}}"); return; } if (fexpr_is_builtin_call(expr, FEXPR_DiagonalMatrix)) { calcium_write(out, "\\displaystyle{\\begin{pmatrix}"); if (nargs > 0) { fexpr_view_arg(elem, expr, 0); for (i = 0; i < nargs; i++) { for (j = 0; j < i; j++) calcium_write(out, " & "); fexpr_write_latex(out, elem, flags); for (j = i + 1; j < nargs; j++) calcium_write(out, " & "); if (i < nargs - 1) { calcium_write(out, " \\\\ "); fexpr_view_next(elem); } } } calcium_write(out, "\\end{pmatrix}}"); return; } if (fexpr_is_builtin_call(expr, FEXPR_Matrix2x2) && nargs == 4) { calcium_write(out, "\\displaystyle{\\begin{pmatrix}"); fexpr_view_arg(elem, expr, 0); fexpr_write_latex(out, elem, flags); calcium_write(out, " & "); fexpr_view_next(elem); fexpr_write_latex(out, elem, flags); calcium_write(out, " \\\\ "); fexpr_view_next(elem); fexpr_write_latex(out, elem, flags); calcium_write(out, " & "); fexpr_view_next(elem); fexpr_write_latex(out, elem, flags); calcium_write(out, "\\end{pmatrix}}"); return; } if (fexpr_is_builtin_call(expr, FEXPR_Matrix) && nargs == 3) { fexpr_t for1, for2, f1, f2, i, a, b, j, c, d; fexpr_view_arg(for1, expr, 1); fexpr_view_arg(for2, expr, 2); if (fexpr_view_call3(f1, i, a, b, for1) && fexpr_view_call3(f2, j, c, d, for2) && fexpr_is_builtin_symbol(f1, FEXPR_For) && fexpr_is_builtin_symbol(f2, FEXPR_For)) { fexpr_t a1, c1, x; fmpz_t n; fmpz_init(n); fexpr_init(a1); fexpr_init(c1); fexpr_init(x); fexpr_view_arg(arg, expr, 0); /* a1 = a + 1 */ if (fexpr_is_integer(a)) { fexpr_get_fmpz(n, a); fmpz_add_ui(n, n, 1); fexpr_set_fmpz(a1, n); } else { fexpr_set_ui(x, 1); fexpr_add(a1, a, x); } /* c1 = c + 1 */ if (fexpr_is_integer(c)) { fexpr_get_fmpz(n, c); fmpz_add_ui(n, n, 1); fexpr_set_fmpz(c1, n); } else { fexpr_set_ui(x, 1); fexpr_add(c1, c, x); } calcium_write(out, "\\displaystyle{\\begin{pmatrix} "); fexpr_replace2(x, arg, i, a, j, c); fexpr_write_latex(out, x, flags); calcium_write(out, " & "); fexpr_replace2(x, arg, i, a, j, c1); fexpr_write_latex(out, x, flags); calcium_write(out, " & \\cdots & "); fexpr_replace2(x, arg, i, a, j, d); fexpr_write_latex(out, x, flags); calcium_write(out, " \\\\ "); fexpr_replace2(x, arg, i, a1, j, c); fexpr_write_latex(out, x, flags); calcium_write(out, " & "); fexpr_replace2(x, arg, i, a1, j, c1); fexpr_write_latex(out, x, flags); calcium_write(out, " & \\cdots & "); fexpr_replace2(x, arg, i, a1, j, d); fexpr_write_latex(out, x, flags); calcium_write(out, " \\\\ "); calcium_write(out, "\\vdots & \\vdots & \\ddots & \\vdots \\\\ "); fexpr_replace2(x, arg, i, b, j, c); fexpr_write_latex(out, x, flags); calcium_write(out, " & "); fexpr_replace2(x, arg, i, b, j, c1); fexpr_write_latex(out, x, flags); calcium_write(out, " & \\cdots & "); fexpr_replace2(x, arg, i, b, j, d); fexpr_write_latex(out, x, flags); calcium_write(out, " \\end{pmatrix}}"); fmpz_clear(n); fexpr_clear(a1); fexpr_clear(c1); fexpr_clear(x); return; } } if (fexpr_is_builtin_call(expr, FEXPR_Matrix) && nargs >= 1) { fexpr_view_arg(arg, expr, 0); /* Todo: handle columns too */ if (fexpr_is_builtin_call(arg, FEXPR_Row)) { nrows = fexpr_nargs(expr); calcium_write(out, "\\displaystyle{\\begin{pmatrix}"); fexpr_view_arg(row, expr, 0); for (i = 0; i < nrows; i++) { ncols = fexpr_nargs(row); if (ncols >= 0) { fexpr_view_arg(elem, row, 0); for (j = 0; j < ncols; j++) { fexpr_write_latex(out, elem, flags); if (j < ncols - 1) { calcium_write(out, " & "); fexpr_view_next(elem); } } } if (i < nrows - 1) { calcium_write(out, " \\\\"); fexpr_view_next(row); } } calcium_write(out, "\\end{pmatrix}}"); return; } } if (nargs == 1) { fexpr_view_arg(arg, expr, 0); if (fexpr_is_builtin_call(arg, FEXPR_Tuple) || fexpr_is_builtin_call(arg, FEXPR_List)) { nrows = fexpr_nargs(arg); calcium_write(out, "\\displaystyle{\\begin{pmatrix}"); fexpr_view_arg(row, arg, 0); for (i = 0; i < nrows; i++) { ncols = fexpr_nargs(row); if (ncols >= 0) { fexpr_view_arg(elem, row, 0); for (j = 0; j < ncols; j++) { fexpr_write_latex(out, elem, flags); if (j < ncols - 1) { calcium_write(out, " & "); fexpr_view_next(elem); } } } if (i < nrows - 1) { calcium_write(out, " \\\\"); fexpr_view_next(row); } } calcium_write(out, "\\end{pmatrix}}"); return; } } fexpr_write_latex_call(out, expr, flags); } void fexpr_write_latex_decimal(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t arg; char * s; slong i, len; if (fexpr_nargs(expr) == 1) { fexpr_view_arg(arg, expr, 0); if (fexpr_is_string(arg)) { s = fexpr_get_string(arg); len = strlen(s); for (i = 0; i < len; i++) { if (s[i] == 'e' || s[i] == 'E') { s[i] = '\0'; calcium_write(out, s); calcium_write(out, " \\cdot 10^{"); calcium_write(out, s + i + 1); calcium_write(out, "}"); flint_free(s); return; } } calcium_write(out, s); flint_free(s); return; } } fexpr_write_latex_call(out, expr, flags); } /* Write (x) */ void _fexpr_write_latex_call1(calcium_stream_t out, const fexpr_t x, ulong flags) { if (fexpr_is_atom(x)) { calcium_write(out, "("); fexpr_write_latex(out, x, flags); calcium_write(out, ")"); } else { calcium_write(out, "\\!\\left("); fexpr_write_latex(out, x, flags); calcium_write(out, "\\right)"); } } static void _write_poly(calcium_stream_t out, const fexpr_t pol, ulong flags) { fexpr_t c; slong i, d; d = fexpr_nargs(pol) - 1; if (d < 0) { calcium_write(out, "0"); return; } for (i = d; i >= 0; i--) { fexpr_view_arg(c, pol, i); if (fexpr_equal_si(c, 0)) continue; if (fexpr_equal_si(c, 1)) { if (i == 0) calcium_write(out, "+1"); else if (i != d) calcium_write(out, "+"); } else if (fexpr_equal_si(c, -1)) { if (i == 0) calcium_write(out, "-1"); else calcium_write(out, "-"); } else { if (fexpr_need_parens_in_mul(c, 0)) { if (i != d) calcium_write(out, "+ "); calcium_write(out, "\\left("); fexpr_write_latex(out, c, flags); calcium_write(out, "\\right)"); } else { if (fexpr_is_integer(c)) { if (!(fexpr_can_extract_leading_sign(c) || i == d)) calcium_write(out, "+"); fexpr_write_latex(out, c, flags); } else { char * s = fexpr_get_str_latex(c, flags); if (s[0] == '+' || s[0] == '-') { calcium_write(out, s); } else { if (i != d) calcium_write(out, " + "); calcium_write(out, s); } flint_free(s); } } } if (i == 1) { calcium_write(out, " x"); } else if (i >= 2) { calcium_write(out, " x^{"); calcium_write_si(out, i); calcium_write(out, "}"); } } } void fexpr_write_latex_misc_special(calcium_stream_t out, const fexpr_t expr, ulong flags) { if (fexpr_is_builtin_call(expr, FEXPR_Polynomial) && fexpr_nargs(expr) == 1) { fexpr_t pol; fexpr_view_arg(pol, expr, 0); _write_poly(out, pol, flags); return; } if (fexpr_is_builtin_call(expr, FEXPR_PolynomialRootNearest) && fexpr_nargs(expr) == 2) { fexpr_t pol, point; fexpr_view_arg(pol, expr, 0); fexpr_view_arg(point, expr, 1); /* calcium_write(out, "\\left(x \\approx "); fexpr_write_latex(out, point, flags); calcium_write(out, ", \\,"); _write_poly(out, pol, flags); calcium_write(out, "= 0\\right)"); return; */ calcium_write(out, "\\left(\\text{Root }\\, "); calcium_write(out, "x \\approx {"); fexpr_write_latex(out, point, flags); calcium_write(out, "} \\;\\text{ of } \\;{"); _write_poly(out, pol, flags); calcium_write(out, "}\\right)"); return; } if (fexpr_is_builtin_call(expr, FEXPR_PolynomialRootIndexed) && fexpr_nargs(expr) == 2) { fexpr_t pol, point; fexpr_view_arg(pol, expr, 0); fexpr_view_arg(point, expr, 1); calcium_write(out, "\\left(\\text{Root \\#}"); fexpr_write_latex(out, point, flags); calcium_write(out, " \\text{ of }\\, {"); _write_poly(out, pol, flags); calcium_write(out, "}\\right)"); return; } /* if (fexpr_is_builtin_call(expr, FEXPR_AlgebraicNumberSerialized) && fexpr_nargs(expr) == 2) { fexpr_t pol, index; fexpr_view_arg(pol, expr, 0); fexpr_view_arg(index, expr, 1); calcium_write(out, "\\left(\\text{Algebraic } "); fexpr_write_latex(out, pol, flags); calcium_write(out, "_{"); fexpr_write_latex(out, index, flags); calcium_write(out, "}\\right)"); return; } */ if (fexpr_is_builtin_call(expr, FEXPR_Call) && fexpr_nargs(expr) == 2) { fexpr_t f, x; fexpr_view_arg(f, expr, 0); fexpr_view_arg(x, expr, 1); fexpr_write_latex(out, f, flags); _fexpr_write_latex_call1(out, x, flags); return; } if (fexpr_is_builtin_call(expr, FEXPR_CallIndeterminate) && fexpr_nargs(expr) == 3) { fexpr_t f, x, v; fexpr_view_arg(f, expr, 0); fexpr_view_arg(x, expr, 1); fexpr_view_arg(v, expr, 2); fexpr_write_latex(out, f, flags); _fexpr_write_latex_call1(out, v, flags); return; } if (fexpr_is_builtin_call(expr, FEXPR_IndefiniteIntegralEqual) && fexpr_nargs(expr) == 3) { fexpr_t fx, gx, x; fexpr_view_arg(fx, expr, 0); fexpr_view_arg(gx, expr, 1); fexpr_view_arg(x, expr, 2); calcium_write(out, "\\int "); fexpr_write_latex(out, fx, flags); calcium_write(out, " \\, d"); fexpr_write_latex(out, x, flags); calcium_write(out, " = "); fexpr_write_latex(out, gx, flags); calcium_write(out, " + \\mathcal{C}"); return; } if (fexpr_is_builtin_call(expr, FEXPR_CurvePath) && fexpr_nargs(expr) == 2) { fexpr_t f, forexpr, x, a, b; slong forexpr_nargs; fexpr_view_arg(f, expr, 0); fexpr_view_arg(forexpr, expr, 1); forexpr_nargs = fexpr_nargs(forexpr); if (forexpr_nargs == 3) { fexpr_view_arg(x, forexpr, 0); fexpr_view_arg(a, forexpr, 1); fexpr_view_arg(b, forexpr, 2); calcium_write(out, "\\left("); fexpr_write_latex(out, f, flags); calcium_write(out, ",\\, "); fexpr_write_latex(out, x, flags); calcium_write(out, " : "); fexpr_write_latex(out, a, flags); calcium_write(out, " \\rightsquigarrow "); fexpr_write_latex(out, b, flags); calcium_write(out, "\\right)"); return; } } if (fexpr_is_builtin_call(expr, FEXPR_AnalyticContinuation) && fexpr_nargs(expr) == 2) { fexpr_t f, forexpr, x, a, b; slong forexpr_nargs; fexpr_view_arg(f, expr, 0); fexpr_view_arg(forexpr, expr, 1); forexpr_nargs = fexpr_nargs(forexpr); if (forexpr_nargs == 2) { fexpr_view_arg(x, forexpr, 0); fexpr_view_arg(a, forexpr, 1); calcium_write(out, "\\mathop{\\text{Continuation}}\\limits_{\\displaystyle{"); fexpr_write_latex(out, x, flags); calcium_write(out, ": "); fexpr_write_latex(out, a, flags); calcium_write(out, "}} \\, "); fexpr_write_latex(out, f, flags); return; } if (forexpr_nargs == 3) { fexpr_view_arg(x, forexpr, 0); fexpr_view_arg(a, forexpr, 1); fexpr_view_arg(b, forexpr, 2); calcium_write(out, "\\mathop{\\text{Continuation}}\\limits_{\\displaystyle{"); fexpr_write_latex(out, x, flags); calcium_write(out, ": "); fexpr_write_latex(out, a, flags); calcium_write(out, " \\rightsquigarrow "); fexpr_write_latex(out, b, flags); calcium_write(out, "}} \\, "); fexpr_write_latex(out, f, flags); return; } } if (fexpr_is_builtin_call(expr, FEXPR_QSeriesCoefficient) && fexpr_nargs(expr) == 5) { fexpr_t f, tau, q, n, qdef; int parens; fexpr_view_arg(f, expr, 0); fexpr_view_arg(tau, expr, 1); fexpr_view_arg(q, expr, 2); fexpr_view_arg(n, expr, 3); fexpr_view_arg(qdef, expr, 4); parens = fexpr_is_builtin_call(f, FEXPR_Add) || fexpr_is_builtin_call(f, FEXPR_Sub); calcium_write(out, "[{"); fexpr_write_latex(out, q, flags); calcium_write(out, "}^{"); fexpr_write_latex(out, n, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}] "); if (parens) calcium_write(out, "\\left("); fexpr_write_latex(out, f, flags); if (parens) calcium_write(out, "\\right)"); calcium_write(out, " \\; \\left("); fexpr_write_latex(out, qdef, flags); calcium_write(out, "\\right)"); return; } if (fexpr_is_builtin_call(expr, FEXPR_EqualQSeriesEllipsis) && fexpr_nargs(expr) == 5) { fexpr_t f, tau, q, ser, qdef; fexpr_view_arg(f, expr, 0); fexpr_view_arg(tau, expr, 1); fexpr_view_arg(q, expr, 2); fexpr_view_arg(ser, expr, 3); fexpr_view_arg(qdef, expr, 4); fexpr_write_latex(out, f, flags); calcium_write(out, " = "); fexpr_write_latex(out, ser, flags | FEXPR_LATEX_SMALL); calcium_write(out, " + \\ldots \\; \\text{ where } "); fexpr_write_latex(out, qdef, flags); return; } if (fexpr_is_builtin_call(expr, FEXPR_Coefficient) && fexpr_nargs(expr) == 3) { fexpr_t f, x, n; int parens; fexpr_view_arg(f, expr, 0); fexpr_view_arg(x, expr, 1); fexpr_view_arg(n, expr, 2); parens = fexpr_is_builtin_call(f, FEXPR_Add) || fexpr_is_builtin_call(f, FEXPR_Sub); calcium_write(out, "[{"); fexpr_write_latex(out, x, flags); calcium_write(out, "}^{"); fexpr_write_latex(out, n, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}] "); if (parens) calcium_write(out, "\\left("); fexpr_write_latex(out, f, flags); if (parens) calcium_write(out, "\\right)"); return; } if (fexpr_is_builtin_call(expr, FEXPR_DiscreteLog) && fexpr_nargs(expr) == 3) { fexpr_t n, b, q; fexpr_view_arg(n, expr, 0); fexpr_view_arg(b, expr, 1); fexpr_view_arg(q, expr, 2); calcium_write(out, "(\\epsilon : {"); /* todo: may need parentheses */ fexpr_write_latex(out, b, flags); calcium_write(out, "}^{\\epsilon} \\equiv "); fexpr_write_latex(out, n, flags); calcium_write(out, " \\text{ mod }"); fexpr_write_latex(out, q, flags); calcium_write(out, ")"); return; } if (fexpr_is_builtin_call(expr, FEXPR_AsymptoticTo) && fexpr_nargs(expr) == 4) { fexpr_t a, b, c, d; fexpr_view_arg(a, expr, 0); fexpr_view_arg(b, expr, 1); fexpr_view_arg(c, expr, 2); fexpr_view_arg(d, expr, 3); fexpr_write_latex(out, a, flags); calcium_write(out, " \\sim "); fexpr_write_latex(out, b, flags); calcium_write(out, ", \\; "); fexpr_write_latex(out, c, flags); calcium_write(out, " \\to "); fexpr_write_latex(out, d, flags); return; } if ((fexpr_is_builtin_call(expr, FEXPR_CoulombF) || fexpr_is_builtin_call(expr, FEXPR_CoulombG)) && fexpr_nargs(expr) == 3) { fexpr_t l, eta, z; fexpr_view_arg(l, expr, 0); fexpr_view_arg(eta, expr, 1); fexpr_view_arg(z, expr, 2); if (fexpr_is_builtin_call(expr, FEXPR_CoulombF)) calcium_write(out, "F_{"); else calcium_write(out, "G_{"); fexpr_write_latex(out, l, flags | FEXPR_LATEX_SMALL); calcium_write(out, ","); fexpr_write_latex(out, eta, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); _fexpr_write_latex_call1(out, z, flags); return; } if (fexpr_is_builtin_call(expr, FEXPR_CoulombH) && fexpr_nargs(expr) == 4) { fexpr_t omega, l, eta, z; fexpr_view_arg(omega, expr, 0); fexpr_view_arg(l, expr, 1); fexpr_view_arg(eta, expr, 2); fexpr_view_arg(z, expr, 3); calcium_write(out, "H^{"); if (fexpr_equal_si(omega, +1)) calcium_write(out, "+"); else if (fexpr_equal_si(omega, -1)) calcium_write(out, "-"); else fexpr_write_latex(out, omega, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}_{"); fexpr_write_latex(out, l, flags | FEXPR_LATEX_SMALL); calcium_write(out, ","); fexpr_write_latex(out, eta, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); _fexpr_write_latex_call1(out, z, flags); return; } if (fexpr_is_builtin_call(expr, FEXPR_Repeat) && fexpr_nargs(expr) >= 2) { slong i, n; fexpr_t x; n = fexpr_nargs(expr) - 1; calcium_write(out, "\\underbrace{"); for (i = 0; i < n; i++) { fexpr_view_arg(x, expr, i); fexpr_write_latex(out, x, flags); if (i < n - 1) calcium_write(out, ", "); } calcium_write(out, ", \\ldots, "); for (i = 0; i < n; i++) { fexpr_view_arg(x, expr, i); fexpr_write_latex(out, x, flags); if (i < n - 1) calcium_write(out, ", "); } calcium_write(out, "}_{"); if (n > 1) { calcium_write(out, "\\left("); for (i = 0; i < n; i++) { fexpr_view_arg(x, expr, i); fexpr_write_latex(out, x, flags); if (i < n - 1) calcium_write(out, ", "); } calcium_write(out, "\\right) \\; "); } fexpr_view_arg(x, expr, n); fexpr_write_latex(out, x, flags); calcium_write(out, " \\text{ times}}"); return; } if (fexpr_is_builtin_call(expr, FEXPR_Matrices)) { fexpr_t R, n, m; if (fexpr_nargs(expr) == 2 || fexpr_nargs(expr) == 3) { fexpr_view_arg(R, expr, 0); fexpr_view_arg(n, expr, 1); calcium_write(out, "\\operatorname{M}_{"); fexpr_write_latex(out, n, flags); if (fexpr_nargs(expr) == 3) { calcium_write(out, " \\times "); fexpr_view_arg(m, expr, 2); fexpr_write_latex(out, m, flags | FEXPR_LATEX_SMALL); } calcium_write(out, "}"); _fexpr_write_latex_call1(out, R, flags); return; } } if (fexpr_is_builtin_call(expr, FEXPR_DirichletCharacter)) { fexpr_t a, b, n; if (fexpr_nargs(expr) == 2 || fexpr_nargs(expr) == 3) { fexpr_view_arg(a, expr, 0); fexpr_view_arg(b, expr, 1); calcium_write(out, "\\chi_{"); fexpr_write_latex(out, a, flags | FEXPR_LATEX_SMALL); calcium_write(out, " \\, . \\, "); fexpr_write_latex(out, b, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); if (fexpr_nargs(expr) == 3) { fexpr_view_arg(n, expr, 2); _fexpr_write_latex_call1(out, n, flags); } return; } } if (fexpr_is_builtin_call(expr, FEXPR_LambertW)) { fexpr_t f, x, n, r; if (fexpr_nargs(expr) == 1) { fexpr_view_arg(n, expr, 0); calcium_write(out, "W"); _fexpr_write_latex_call1(out, n, flags); return; } if (fexpr_nargs(expr) == 2) { fexpr_view_arg(x, expr, 0); fexpr_view_arg(n, expr, 1); calcium_write(out, "W_{"); fexpr_write_latex(out, n, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); _fexpr_write_latex_call1(out, x, flags); return; } if (fexpr_nargs(expr) == 3) { fexpr_view_func(f, expr); fexpr_view_arg(x, expr, 0); fexpr_view_arg(n, expr, 1); fexpr_view_arg(r, expr, 2); _fexpr_write_latex_derivative(out, f, NULL, r, flags); calcium_write(out, "_{"); fexpr_write_latex(out, n, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); _fexpr_write_latex_call1(out, x, flags); return; } } if (fexpr_is_builtin_call(expr, FEXPR_SloaneA) && fexpr_nargs(expr) == 2) { fexpr_t x, n; fexpr_view_arg(x, expr, 0); fexpr_view_arg(n, expr, 1); calcium_write(out, "\\text{"); if (fexpr_is_integer(x)) { fmpz_t t; fmpz_init(t); fexpr_get_fmpz(t, x); if (fmpz_cmp_ui(t, 10) < 0) calcium_write(out, "A00000"); else if (fmpz_cmp_ui(t, 100) < 0) calcium_write(out, "A0000"); else if (fmpz_cmp_ui(t, 1000) < 0) calcium_write(out, "A000"); else if (fmpz_cmp_ui(t, 10000) < 0) calcium_write(out, "A00"); else if (fmpz_cmp_ui(t, 100000) < 0) calcium_write(out, "A0"); else calcium_write(out, "A"); calcium_write_fmpz(out, t); fmpz_clear(t); } else if (fexpr_is_string(x)) { char * s = fexpr_get_string(x); if (s[0] != 'A') calcium_write(out, "A"); calcium_write_free(out, s); } else { calcium_write(out, "A00000"); fexpr_write_latex(out, x, flags); } calcium_write(out, "}\\!\\left("); fexpr_write_latex(out, n, flags); calcium_write(out, "\\right)"); return; } if (fexpr_is_builtin_call(expr, FEXPR_EqualAndElement)) { fexpr_t a, b, c; if (fexpr_nargs(expr) == 3) { fexpr_view_arg(a, expr, 0); fexpr_view_arg(b, expr, 1); fexpr_view_arg(c, expr, 2); fexpr_write_latex(out, a, flags); calcium_write(out, " = "); fexpr_write_latex(out, b, flags); calcium_write(out, " \\in "); fexpr_write_latex(out, c, flags); return; } } if (fexpr_is_builtin_call(expr, FEXPR_EqualNearestDecimal)) { fexpr_t a, b, c; if (fexpr_nargs(expr) == 3) { fexpr_view_arg(a, expr, 0); fexpr_view_arg(b, expr, 1); fexpr_view_arg(c, expr, 2); fexpr_write_latex(out, a, flags); calcium_write(out, " = "); fexpr_write_latex(out, b, flags); calcium_write(out, " \\;\\, {\\scriptstyle (\\text{nearest } "); fexpr_write_latex(out, c, flags); calcium_write(out, " \\text{ digits})}"); return; } } if (fexpr_is_builtin_call(expr, FEXPR_IsHolomorphicOn) || fexpr_is_builtin_call(expr, FEXPR_IsMeromorphicOn)) { if (fexpr_nargs(expr) == 2) { fexpr_t func, forexpr; fexpr_view_arg(func, expr, 0); fexpr_view_arg(forexpr, expr, 1); if (fexpr_nargs(forexpr) == 2) { fexpr_t var, domain; fexpr_view_arg(var, forexpr, 0); fexpr_view_arg(domain, forexpr, 1); fexpr_write_latex(out, func, flags); if (fexpr_is_builtin_call(expr, FEXPR_IsHolomorphicOn)) calcium_write(out, " \\text{ is holomorphic on } "); else calcium_write(out, " \\text{ is meromorphic on } "); fexpr_write_latex(out, var, flags); calcium_write(out, " \\in "); fexpr_write_latex(out, domain, flags); return; } } } fexpr_write_latex_call(out, expr, flags); } void fexpr_write_latex_show_form(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t f, arg; if (fexpr_view_call1(f, arg, expr) && fexpr_is_builtin_symbol(f, FEXPR_ShowExpandedNormalForm)) { fexpr_t v; fexpr_init(v); fexpr_expanded_normal_form(v, arg, 0); fexpr_write_latex(out, v, flags); fexpr_clear(v); return; } fexpr_write_latex_call(out, expr, flags); } void fexpr_write_latex_alg_structure(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t func, arg; const char *a; const char *b; slong i, nargs; nargs = fexpr_nargs(expr); if (nargs <= 1) { fexpr_write_latex_call(out, expr, flags); return; } fexpr_view_func(func, expr); fexpr_view_arg(arg, expr, 0); i = FEXPR_BUILTIN_ID(func->data[0]); switch (i) { case FEXPR_Polynomials: a = "["; b = "]"; break; case FEXPR_PolynomialFractions: a = "("; b = ")"; break; case FEXPR_FormalPowerSeries: a = "[["; b = "]]"; break; case FEXPR_FormalLaurentSeries: a = "(\\!("; b = ")\\!)"; break; case FEXPR_FormalPuiseuxSeries: a = "\\!\\left\\langle\\!\\left\\langle "; b = " \\right\\rangle\\!\\right\\rangle"; break; default: fexpr_write_latex_call(out, expr, flags); return; } fexpr_write_latex(out, arg, flags); calcium_write(out, a); if (nargs >= 1) { slong i; fexpr_view_next(arg); if (fexpr_is_builtin_call(arg, FEXPR_Tuple)) { nargs = fexpr_nargs(arg); fexpr_view_arg(arg, arg, 0); } else { nargs--; } for (i = 0; i < nargs; i++) { fexpr_write_latex(out, arg, flags); if (i < nargs - 1) { calcium_write(out, ", "); fexpr_view_next(arg); } } } calcium_write(out, b); } void fexpr_write_latex_where(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t f, arg, x, val; slong i, nargs; nargs = fexpr_nargs(expr); if (nargs > 0) { fexpr_view_arg(f, expr, 0); fexpr_write_latex(out, f, flags); } if (nargs > 1) { calcium_write(out, "\\; \\text{ where } "); fexpr_view_arg(arg, expr, 1); for (i = 1; i < nargs; i++) { if (fexpr_nargs(arg) == 2) { fexpr_view_arg(x, arg, 0); fexpr_view_arg(val, arg, 1); fexpr_write_latex(out, x, flags); calcium_write(out, " = "); fexpr_write_latex(out, val, flags); if (i < nargs - 1) { calcium_write(out, ",\\;"); fexpr_view_next(arg); } } } } } static int _fexpr_all_arguments_small(const fexpr_t expr) { fexpr_t arg; slong i, nargs; nargs = fexpr_nargs(expr); fexpr_view_arg(arg, expr, 0); for (i = 0; i < nargs; i++) { if (!fexpr_is_atom(arg)) return 0; fexpr_view_next(arg); } return 1; } void fexpr_write_latex_symbol(int * subscript, calcium_stream_t out, const fexpr_t expr, ulong flags) { if (fexpr_is_any_builtin_symbol(expr)) { slong i; i = FEXPR_BUILTIN_ID(expr->data[0]); if (strcmp(fexpr_builtin_table[i].latex_string, "")) { calcium_write(out, fexpr_builtin_table[i].latex_string); } else { calcium_write(out, "\\operatorname{"); calcium_write(out, fexpr_builtin_table[i].string); calcium_write(out, "}"); } *subscript = 0; } else if (fexpr_is_symbol(expr)) { const char *s; char tmp[FEXPR_SMALL_SYMBOL_LEN + 1]; slong i, len; s = fexpr_get_symbol_str_pointer(tmp, expr); len = strlen(s); if (len > 1 && s[len - 1] == '_') { char * tmp2; tmp2 = flint_malloc(len); memcpy(tmp2, tmp, len - 1); tmp2[len - 1] = '\0'; calcium_write(out, tmp2); *subscript = 1; flint_free(tmp2); } else if (len == 1) { calcium_write(out, s); *subscript = 0; } else { /* Look for internal underscore */ slong pos = 0; for (i = 1; i < len - 1; i++) { if (s[i] == '_') { pos = i; break; } } if (pos == 0) { calcium_write(out, "\\operatorname{"); calcium_write(out, s); calcium_write(out, "}"); *subscript = 0; } else { char * tmp2; tmp2 = flint_malloc(len); memcpy(tmp2, tmp, pos); tmp2[pos] = '\0'; if (pos == 1) { calcium_write(out, tmp2); } else { calcium_write(out, "\\operatorname{"); calcium_write(out, tmp2); calcium_write(out, "}"); } calcium_write(out, "_{"); calcium_write(out, s + pos + 1); calcium_write(out, "}"); flint_free(tmp2); *subscript = 0; } } } else { if (fexpr_is_builtin_call(expr, FEXPR_Add) || fexpr_is_builtin_call(expr, FEXPR_Sub) || fexpr_is_builtin_call(expr, FEXPR_Mul) || fexpr_is_builtin_call(expr, FEXPR_Div) || fexpr_is_builtin_call(expr, FEXPR_Neg) || fexpr_is_builtin_call(expr, FEXPR_Pos)) { calcium_write(out, "\\left("); fexpr_write_latex(out, expr, flags); calcium_write(out, "\\right)"); *subscript = 0; } else { fexpr_write_latex(out, expr, flags); *subscript = 0; } } } void fexpr_write_latex_call(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t view; slong i, nargs; int small, subscript; nargs = fexpr_nargs(expr); fexpr_view_func(view, expr); fexpr_write_latex_symbol(&subscript, out, view, flags); if (subscript) { calcium_write(out, "_{"); for (i = 0; i < nargs; i++) { fexpr_view_next(view); fexpr_write_latex(out, view, flags | FEXPR_LATEX_SMALL); if (i < nargs - 1) calcium_write(out, ", "); } calcium_write(out, "}"); } else { fexpr_view_next(view); /* Function of matrix already has parentheses */ if (nargs == 1) { if (fexpr_is_builtin_call(view, FEXPR_Matrix) || fexpr_is_builtin_call(view, FEXPR_Matrix2x2)) { calcium_write(out, " "); fexpr_write_latex(out, view, flags); return; } } small = _fexpr_all_arguments_small(expr); if (small) calcium_write(out, "("); else calcium_write(out, "\\!\\left("); for (i = 0; i < nargs; i++) { fexpr_write_latex(out, view, flags); if (i < nargs - 1) { calcium_write(out, ", "); fexpr_view_next(view); } } if (small) calcium_write(out, ")"); else calcium_write(out, "\\right)"); } } void fexpr_write_latex_subscript_call(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t view; slong i, nargs; int subscript; nargs = fexpr_nargs(expr); fexpr_view_func(view, expr); fexpr_write_latex_symbol(&subscript, out, view, flags); if (nargs >= 1) { calcium_write(out, "_{"); fexpr_view_next(view); fexpr_write_latex(out, view, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); } if (nargs >= 2) { calcium_write(out, "\\!\\left("); for (i = 1; i < nargs; i++) { fexpr_view_next(view); fexpr_write_latex(out, view, flags); if (i < nargs - 1) calcium_write(out, ", "); } calcium_write(out, "\\right)"); } } void fexpr_write_latex_subscript(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t view; slong i, nargs; int subscript; nargs = fexpr_nargs(expr); fexpr_view_func(view, expr); fexpr_write_latex_symbol(&subscript, out, view, flags); calcium_write(out, "_{"); for (i = 0; i < nargs; i++) { fexpr_view_next(view); fexpr_write_latex(out, view, flags | FEXPR_LATEX_SMALL); if (i < nargs - 1) calcium_write(out, ", "); } calcium_write(out, "}"); } /* f(x) */ /* f(x,n) -> nth derivative */ void fexpr_write_latex_call1_optional_derivative(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t func, x, order; slong nargs; nargs = fexpr_nargs(expr); if (nargs == 2) { fexpr_view_func(func, expr); fexpr_view_arg(x, expr, 0); fexpr_view_arg(order, expr, 1); _fexpr_write_latex_derivative(out, func, NULL, order, flags); calcium_write(out, "\\!\\left("); fexpr_write_latex(out, x, flags); calcium_write(out, "\\right)"); } else { fexpr_write_latex_call(out, expr, flags); } } /* f(x,y) */ /* f(x,y,n) -> nth derivative */ void fexpr_write_latex_call2_optional_derivative(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t func, x, y, order; slong nargs; nargs = fexpr_nargs(expr); if (nargs == 3) { fexpr_view_func(func, expr); fexpr_view_arg(x, expr, 0); fexpr_view_arg(y, expr, 1); fexpr_view_arg(order, expr, 2); _fexpr_write_latex_derivative(out, func, NULL, order, flags); calcium_write(out, "\\!\\left("); fexpr_write_latex(out, x, flags); calcium_write(out, ", "); fexpr_write_latex(out, y, flags); calcium_write(out, "\\right)"); } else { fexpr_write_latex_call(out, expr, flags); } } /* f_x(y) */ /* f_x(y,n) -> nth derivative */ void fexpr_write_latex_sub1_call1_optional_derivative(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t func, x, y, order; slong nargs; nargs = fexpr_nargs(expr); if (nargs == 3) { fexpr_view_func(func, expr); fexpr_view_arg(x, expr, 0); fexpr_view_arg(y, expr, 1); fexpr_view_arg(order, expr, 2); _fexpr_write_latex_derivative(out, func, NULL, order, flags); calcium_write(out, "_{"); fexpr_write_latex(out, x, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); calcium_write(out, "\\!\\left("); fexpr_write_latex(out, y, flags); calcium_write(out, "\\right)"); } else { fexpr_write_latex_subscript_call(out, expr, flags); } } /* f_x(y,z) */ /* f_x(y,z,n) -> nth derivative */ void fexpr_write_latex_sub1_call2_optional_derivative(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t func, x, y, z, order; slong nargs; nargs = fexpr_nargs(expr); if (nargs == 4) { fexpr_view_func(func, expr); fexpr_view_arg(x, expr, 0); fexpr_view_arg(y, expr, 1); fexpr_view_arg(z, expr, 2); fexpr_view_arg(order, expr, 3); _fexpr_write_latex_derivative(out, func, NULL, order, flags); calcium_write(out, "_{"); fexpr_write_latex(out, x, flags | FEXPR_LATEX_SMALL); calcium_write(out, "}"); calcium_write(out, "\\!\\left("); fexpr_write_latex(out, y, flags); calcium_write(out, ", "); fexpr_write_latex(out, z, flags); calcium_write(out, "\\right)"); } else { fexpr_write_latex_subscript_call(out, expr, flags); } } void fexpr_write_latex_infix(calcium_stream_t out, const fexpr_t expr, ulong flags) { fexpr_t func, arg; slong i, nargs; nargs = fexpr_nargs(expr); fexpr_view_func(func, expr); fexpr_view_func(arg, expr); for (i = 0; i < nargs; i++) { fexpr_view_next(arg); if (fexpr_is_builtin_call(arg, FEXPR_Step) && fexpr_nargs(arg) == 2) { fexpr_t x, forexpr, n, a, b, na, na1, nb; fmpz_t t; fexpr_view_arg(x, arg, 0); fexpr_view_arg(forexpr, arg, 1); if (fexpr_nargs(forexpr) == 3) { fexpr_view_arg(n, forexpr, 0); fexpr_view_arg(a, forexpr, 1); fexpr_view_arg(b, forexpr, 2); fexpr_init(na); fexpr_init(na1); fexpr_init(nb); fmpz_init(t); fexpr_replace(na, x, n, a); if (fexpr_is_integer(a)) { fexpr_get_fmpz(t, a); fmpz_add_ui(t, t, 1); fexpr_set_fmpz(na1, t); fexpr_swap(nb, na1); fexpr_replace(na1, x, n, nb); } else { fexpr_set_ui(nb, 1); fexpr_add(na1, a, nb); fexpr_swap(nb, na1); fexpr_replace(na1, x, n, nb); } fexpr_replace(nb, x, n, b); fexpr_write_latex(out, na, flags); calcium_write(out, " "); fexpr_write_latex(out, func, flags); calcium_write(out, " "); fexpr_write_latex(out, na1, flags); calcium_write(out, " "); fexpr_write_latex(out, func, flags); calcium_write(out, " \\ldots "); fexpr_write_latex(out, func, flags); calcium_write(out, " "); fexpr_write_latex(out, nb, flags); fexpr_clear(na); fexpr_clear(na1); fexpr_clear(nb); fmpz_clear(t); } else { fexpr_write_latex(out, arg, flags); } } else { fexpr_write_latex(out, arg, flags); } if (i < nargs - 1) { calcium_write(out, " "); fexpr_write_latex(out, func, flags); calcium_write(out, " "); } } } void fexpr_write_latex(calcium_stream_t out, const fexpr_t expr, ulong flags) { if (fexpr_is_atom(expr)) { if (fexpr_is_integer(expr)) { fexpr_write(out, expr); } else if (fexpr_is_string(expr)) { char * s; /* todo: escape strings */ s = fexpr_get_string(expr); calcium_write(out, "\\text{``"); calcium_write(out, s); calcium_write(out, "''}"); flint_free(s); } else { int subscript; fexpr_write_latex_symbol(&subscript, out, expr, flags); } } else { fexpr_t func; slong i; fexpr_view_func(func, expr); if (fexpr_is_any_builtin_symbol(func)) { i = FEXPR_BUILTIN_ID(func->data[0]); if (fexpr_builtin_table[i].latex_writer != NULL) { (fexpr_builtin_table[i].latex_writer)(out, expr, flags); return; } } fexpr_write_latex_call(out, expr, flags); } } void fexpr_print_latex(const fexpr_t expr, ulong flags) { calcium_stream_t t; calcium_stream_init_file(t, stdout); fexpr_write_latex(t, expr, flags); } char * fexpr_get_str_latex(const fexpr_t expr, ulong flags) { calcium_stream_t t; calcium_stream_init_str(t); fexpr_write_latex(t, expr, flags); return t->s; } calcium-0.4.1/fexpr_builtin.h000066400000000000000000000301511407704557200161670ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef FEXPR_BUILTIN_H #define FEXPR_BUILTIN_H #ifdef FEXPR_BUILTIN_INLINES_C #define FEXPR_BUILTIN_INLINE #else #define FEXPR_BUILTIN_INLINE static __inline__ #endif #ifdef __cplusplus extern "C" { #endif #include "fexpr.h" /* Builtin symbols */ /* Must be listed in alphabetical order with corresponding entry in fexpr_builtin_table (the alphabetical order is just so that we can do binary search on the strings). */ typedef enum { FEXPR_AGM, FEXPR_AGMSequence, FEXPR_Abs, FEXPR_Acos, FEXPR_Acosh, FEXPR_Acot, FEXPR_Acoth, FEXPR_Acsc, FEXPR_Acsch, FEXPR_Add, FEXPR_AiryAi, FEXPR_AiryAiZero, FEXPR_AiryBi, FEXPR_AiryBiZero, FEXPR_AlgebraicNumberSerialized, FEXPR_AlgebraicNumbers, FEXPR_All, FEXPR_AnalyticContinuation, FEXPR_And, FEXPR_AngleBrackets, FEXPR_Approximation, FEXPR_Arg, FEXPR_ArgMax, FEXPR_ArgMaxUnique, FEXPR_ArgMin, FEXPR_ArgMinUnique, FEXPR_Asec, FEXPR_Asech, FEXPR_Asin, FEXPR_Asinh, FEXPR_AsymptoticTo, FEXPR_Atan, FEXPR_Atan2, FEXPR_Atanh, FEXPR_BarnesG, FEXPR_BellNumber, FEXPR_BernoulliB, FEXPR_BernoulliPolynomial, FEXPR_BernsteinEllipse, FEXPR_BesselI, FEXPR_BesselJ, FEXPR_BesselJZero, FEXPR_BesselK, FEXPR_BesselY, FEXPR_BesselYZero, FEXPR_BetaFunction, FEXPR_Binomial, FEXPR_Braces, FEXPR_Brackets, FEXPR_CC, FEXPR_Call, FEXPR_CallIndeterminate, FEXPR_Cardinality, FEXPR_CarlsonHypergeometricR, FEXPR_CarlsonHypergeometricT, FEXPR_CarlsonRC, FEXPR_CarlsonRD, FEXPR_CarlsonRF, FEXPR_CarlsonRG, FEXPR_CarlsonRJ, FEXPR_CartesianPower, FEXPR_CartesianProduct, FEXPR_Case, FEXPR_Cases, FEXPR_CatalanConstant, FEXPR_Ceil, FEXPR_Characteristic, FEXPR_ChebyshevT, FEXPR_ChebyshevU, FEXPR_ClosedComplexDisk, FEXPR_ClosedOpenInterval, FEXPR_Coefficient, FEXPR_Column, FEXPR_ColumnMatrix, FEXPR_CommutativeRings, FEXPR_ComplexBranchDerivative, FEXPR_ComplexDerivative, FEXPR_ComplexInfinities, FEXPR_ComplexLimit, FEXPR_ComplexSignedInfinities, FEXPR_ComplexSingularityClosure, FEXPR_ComplexZeroMultiplicity, FEXPR_Concatenation, FEXPR_CongruentMod, FEXPR_Conjugate, FEXPR_ConreyGenerator, FEXPR_Cos, FEXPR_CosIntegral, FEXPR_Cosh, FEXPR_CoshIntegral, FEXPR_Cot, FEXPR_Coth, FEXPR_CoulombC, FEXPR_CoulombF, FEXPR_CoulombG, FEXPR_CoulombH, FEXPR_CoulombSigma, FEXPR_Csc, FEXPR_Csch, FEXPR_Csgn, FEXPR_CurvePath, FEXPR_Cyclotomic, FEXPR_Decimal, FEXPR_DedekindEta, FEXPR_DedekindEtaEpsilon, FEXPR_DedekindSum, FEXPR_Def, FEXPR_Delta, FEXPR_Delta_, FEXPR_Derivative, FEXPR_Det, FEXPR_DiagonalMatrix, FEXPR_DigammaFunction, FEXPR_DigammaFunctionZero, FEXPR_DirichletCharacter, FEXPR_DirichletGroup, FEXPR_DirichletL, FEXPR_DirichletLZero, FEXPR_DirichletLambda, FEXPR_DiscreteLog, FEXPR_Div, FEXPR_Divides, FEXPR_DivisorProduct, FEXPR_DivisorSigma, FEXPR_DivisorSum, FEXPR_DoubleFactorial, FEXPR_EisensteinE, FEXPR_EisensteinG, FEXPR_Element, FEXPR_Ellipsis, FEXPR_EllipticE, FEXPR_EllipticK, FEXPR_EllipticPi, FEXPR_EllipticRootE, FEXPR_Enclosure, FEXPR_Equal, FEXPR_EqualAndElement, FEXPR_EqualNearestDecimal, FEXPR_EqualQSeriesEllipsis, FEXPR_Equivalent, FEXPR_Erf, FEXPR_Erfc, FEXPR_Erfi, FEXPR_Euler, FEXPR_EulerE, FEXPR_EulerPhi, FEXPR_EulerPolynomial, FEXPR_EulerQSeries, FEXPR_Exists, FEXPR_Exp, FEXPR_ExpIntegralE, FEXPR_ExpIntegralEi, FEXPR_ExtendedRealNumbers, FEXPR_Factorial, FEXPR_FallingFactorial, FEXPR_False, FEXPR_Fibonacci, FEXPR_Fields, FEXPR_FiniteField, FEXPR_Floor, FEXPR_For, FEXPR_FormalLaurentSeries, FEXPR_FormalPowerSeries, FEXPR_FormalPuiseuxSeries, FEXPR_FresnelC, FEXPR_FresnelS, FEXPR_Fun, FEXPR_GCD, FEXPR_Gamma, FEXPR_GaussLegendreWeight, FEXPR_GaussSum, FEXPR_GegenbauerC, FEXPR_GeneralLinearGroup, FEXPR_GeneralizedBernoulliB, FEXPR_GeneralizedRiemannHypothesis, FEXPR_GlaisherConstant, FEXPR_GoldenRatio, FEXPR_Greater, FEXPR_GreaterEqual, FEXPR_GreekGamma, FEXPR_GreekGamma_, FEXPR_GreekPi, FEXPR_GreekPi_, FEXPR_Guess, FEXPR_HankelH1, FEXPR_HankelH2, FEXPR_HarmonicNumber, FEXPR_HermiteH, FEXPR_HilbertClassPolynomial, FEXPR_HilbertMatrix, FEXPR_HurwitzZeta, FEXPR_Hypergeometric0F1, FEXPR_Hypergeometric0F1Regularized, FEXPR_Hypergeometric1F1, FEXPR_Hypergeometric1F1Regularized, FEXPR_Hypergeometric1F2, FEXPR_Hypergeometric1F2Regularized, FEXPR_Hypergeometric2F0, FEXPR_Hypergeometric2F1, FEXPR_Hypergeometric2F1Regularized, FEXPR_Hypergeometric2F2, FEXPR_Hypergeometric2F2Regularized, FEXPR_Hypergeometric3F2, FEXPR_Hypergeometric3F2Regularized, FEXPR_HypergeometricU, FEXPR_HypergeometricUStar, FEXPR_HypergeometricUStarRemainder, FEXPR_IdentityMatrix, FEXPR_Im, FEXPR_Implies, FEXPR_IncompleteBeta, FEXPR_IncompleteBetaRegularized, FEXPR_IncompleteEllipticE, FEXPR_IncompleteEllipticF, FEXPR_IncompleteEllipticPi, FEXPR_IndefiniteIntegralEqual, FEXPR_Infimum, FEXPR_Infinity, FEXPR_IntegersGreaterEqual, FEXPR_IntegersLessEqual, FEXPR_Integral, FEXPR_Intersection, FEXPR_Interval, FEXPR_IsEven, FEXPR_IsHolomorphicOn, FEXPR_IsMeromorphicOn, FEXPR_IsOdd, FEXPR_IsPrime, FEXPR_Item, FEXPR_JacobiP, FEXPR_JacobiSymbol, FEXPR_JacobiTheta, FEXPR_JacobiThetaEpsilon, FEXPR_JacobiThetaPermutation, FEXPR_JacobiThetaQ, FEXPR_KeiperLiLambda, FEXPR_KhinchinConstant, FEXPR_KroneckerDelta, FEXPR_KroneckerSymbol, FEXPR_LCM, FEXPR_LaguerreL, FEXPR_LambertW, FEXPR_Lamda, FEXPR_Lamda_, FEXPR_LandauG, FEXPR_Lattice, FEXPR_LeftLimit, FEXPR_LegendreP, FEXPR_LegendrePolynomialZero, FEXPR_LegendreSymbol, FEXPR_Length, FEXPR_LerchPhi, FEXPR_Less, FEXPR_LessEqual, FEXPR_Limit, FEXPR_LiouvilleLambda, FEXPR_List, FEXPR_Log, FEXPR_LogBarnesG, FEXPR_LogBarnesGRemainder, FEXPR_LogGamma, FEXPR_LogIntegral, FEXPR_Logic, FEXPR_LowerGamma, FEXPR_Matrices, FEXPR_Matrix, FEXPR_Matrix2x2, FEXPR_Max, FEXPR_Maximum, FEXPR_MeromorphicDerivative, FEXPR_MeromorphicLimit, FEXPR_Min, FEXPR_Minimum, FEXPR_Mod, FEXPR_ModularGroupAction, FEXPR_ModularGroupFundamentalDomain, FEXPR_ModularJ, FEXPR_ModularLambda, FEXPR_ModularLambdaFundamentalDomain, FEXPR_MoebiusMu, FEXPR_Mul, FEXPR_MultiZetaValue, FEXPR_NN, FEXPR_Neg, FEXPR_Not, FEXPR_NotElement, FEXPR_NotEqual, FEXPR_NumberE, FEXPR_NumberI, FEXPR_Omega, FEXPR_Omega_, FEXPR_One, FEXPR_OpenClosedInterval, FEXPR_OpenComplexDisk, FEXPR_OpenInterval, FEXPR_OpenRealBall, FEXPR_Or, FEXPR_Otherwise, FEXPR_PSL2Z, FEXPR_Parentheses, FEXPR_PartitionsP, FEXPR_Path, FEXPR_Phi, FEXPR_Phi_, FEXPR_Pi, FEXPR_Pol, FEXPR_Poles, FEXPR_PolyLog, FEXPR_Polynomial, FEXPR_PolynomialDegree, FEXPR_PolynomialFractions, FEXPR_PolynomialRootIndexed, FEXPR_PolynomialRootNearest, FEXPR_Polynomials, FEXPR_Pos, FEXPR_Pow, FEXPR_Prime, FEXPR_PrimePi, FEXPR_PrimeProduct, FEXPR_PrimeSum, FEXPR_Primes, FEXPR_PrimitiveDirichletCharacters, FEXPR_PrimitiveReducedPositiveIntegralBinaryQuadraticForms, FEXPR_Product, FEXPR_ProjectiveComplexNumbers, FEXPR_ProjectiveRealNumbers, FEXPR_Psi, FEXPR_Psi_, FEXPR_QQ, FEXPR_QSeriesCoefficient, FEXPR_QuotientRing, FEXPR_RR, FEXPR_Range, FEXPR_Re, FEXPR_RealAbs, FEXPR_RealAlgebraicNumbers, FEXPR_RealBall, FEXPR_RealDerivative, FEXPR_RealInfinities, FEXPR_RealLimit, FEXPR_RealSignedInfinities, FEXPR_RealSingularityClosure, FEXPR_Repeat, FEXPR_Residue, FEXPR_RiemannHypothesis, FEXPR_RiemannXi, FEXPR_RiemannZeta, FEXPR_RiemannZetaZero, FEXPR_RightLimit, FEXPR_Rings, FEXPR_RisingFactorial, FEXPR_Root, FEXPR_RootOfUnity, FEXPR_Row, FEXPR_RowMatrix, FEXPR_SL2Z, FEXPR_Same, FEXPR_Sec, FEXPR_Sech, FEXPR_SequenceLimit, FEXPR_SequenceLimitInferior, FEXPR_SequenceLimitSuperior, FEXPR_Ser, FEXPR_Set, FEXPR_SetMinus, FEXPR_Sets, FEXPR_ShowExpandedNormalForm, FEXPR_Sigma, FEXPR_Sigma_, FEXPR_Sign, FEXPR_SignExtendedComplexNumbers, FEXPR_Sin, FEXPR_SinIntegral, FEXPR_Sinc, FEXPR_SingularValues, FEXPR_Sinh, FEXPR_SinhIntegral, FEXPR_SloaneA, FEXPR_Solutions, FEXPR_SpecialLinearGroup, FEXPR_Spectrum, FEXPR_SphericalHarmonicY, FEXPR_Sqrt, FEXPR_SquaresR, FEXPR_Step, FEXPR_StieltjesGamma, FEXPR_StirlingCycle, FEXPR_StirlingS1, FEXPR_StirlingS2, FEXPR_StirlingSeriesRemainder, FEXPR_Sub, FEXPR_Subscript, FEXPR_Subset, FEXPR_SubsetEqual, FEXPR_Subsets, FEXPR_Sum, FEXPR_Supremum, FEXPR_SymmetricPolynomial, FEXPR_Tan, FEXPR_Tanh, FEXPR_Theta, FEXPR_Theta_, FEXPR_True, FEXPR_Tuple, FEXPR_Tuples, FEXPR_Undefined, FEXPR_Union, FEXPR_UniqueSolution, FEXPR_UniqueZero, FEXPR_UnitCircle, FEXPR_Unknown, FEXPR_UnsignedInfinity, FEXPR_UpperGamma, FEXPR_UpperHalfPlane, FEXPR_WeierstrassP, FEXPR_WeierstrassSigma, FEXPR_WeierstrassZeta, FEXPR_Where, FEXPR_XGCD, FEXPR_XX, FEXPR_Xi, FEXPR_Xi_, FEXPR_ZZ, FEXPR_Zero, FEXPR_ZeroMatrix, FEXPR_Zeros, FEXPR_alpha, FEXPR_alpha_, FEXPR_beta, FEXPR_beta_, FEXPR_chi, FEXPR_chi_, FEXPR_delta, FEXPR_delta_, FEXPR_ell, FEXPR_ell_, FEXPR_epsilon, FEXPR_epsilon_, FEXPR_eta, FEXPR_eta_, FEXPR_gamma, FEXPR_gamma_, FEXPR_iota, FEXPR_iota_, FEXPR_kappa, FEXPR_kappa_, FEXPR_lamda, FEXPR_lamda_, FEXPR_mu, FEXPR_mu_, FEXPR_nu, FEXPR_nu_, FEXPR_omega, FEXPR_omega_, FEXPR_phi, FEXPR_phi_, FEXPR_pi, FEXPR_pi_, FEXPR_rho, FEXPR_rho_, FEXPR_sigma, FEXPR_sigma_, FEXPR_tau, FEXPR_tau_, FEXPR_theta, FEXPR_theta_, FEXPR_varphi, FEXPR_varphi_, FEXPR_vartheta, FEXPR_vartheta_, FEXPR_xi, FEXPR_xi_, FEXPR_zeta, FEXPR_zeta_, FEXPR_BUILTIN_LENGTH } fexpr_builtin_symbol; typedef void (*_fexpr_latex_writer)(calcium_stream_t, const fexpr_t, ulong); typedef struct { fexpr_builtin_symbol symbol; const char * string; const char * latex_string; _fexpr_latex_writer latex_writer; } fexpr_symbol_info; extern const fexpr_symbol_info fexpr_builtin_table[FEXPR_BUILTIN_LENGTH]; #define FEXPR_SYMBOL_Pos (FEXPR_TYPE_SMALL_SYMBOL | (FEXPR_Pos << 16)) #define FEXPR_SYMBOL_Neg (FEXPR_TYPE_SMALL_SYMBOL | (FEXPR_Neg << 16)) #define FEXPR_SYMBOL_Add (FEXPR_TYPE_SMALL_SYMBOL | (FEXPR_Add << 16)) #define FEXPR_SYMBOL_Sub (FEXPR_TYPE_SMALL_SYMBOL | (FEXPR_Sub << 16)) #define FEXPR_SYMBOL_Mul (FEXPR_TYPE_SMALL_SYMBOL | (FEXPR_Mul << 16)) #define FEXPR_SYMBOL_Div (FEXPR_TYPE_SMALL_SYMBOL | (FEXPR_Div << 16)) #define FEXPR_SYMBOL_Pow (FEXPR_TYPE_SMALL_SYMBOL | (FEXPR_Pow << 16)) slong fexpr_builtin_lookup(const char * s); FEXPR_BUILTIN_INLINE const char * fexpr_builtin_name(slong n) { return fexpr_builtin_table[n].string; } FEXPR_BUILTIN_INLINE slong fexpr_builtin_length(void) { return FEXPR_BUILTIN_LENGTH; } #ifdef __cplusplus } #endif #endif calcium-0.4.1/fexpr_builtin/000077500000000000000000000000001407704557200160165ustar00rootroot00000000000000calcium-0.4.1/fexpr_builtin/inlines.c000066400000000000000000000007001407704557200176200ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #define FEXPR_BUILTIN_INLINES_C #include "fexpr_builtin.h" calcium-0.4.1/fexpr_builtin/lookup.c000066400000000000000000000014771407704557200175040ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" slong fexpr_builtin_lookup(const char * s) { slong a, mid, b; int cmp; a = 0; b = FEXPR_BUILTIN_LENGTH - 1; while (a <= b) { mid = (a + b) / 2; cmp = strcmp(fexpr_builtin_table[mid].string, s); if (cmp == 0) return mid; else if (cmp > 0) b = mid - 1; else a = mid + 1; } return -1; } calcium-0.4.1/fexpr_builtin/table.c000066400000000000000000001016661407704557200172630ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fexpr.h" #include "fexpr_builtin.h" const fexpr_symbol_info fexpr_builtin_table[FEXPR_BUILTIN_LENGTH] = { { FEXPR_AGM, "AGM", "\\operatorname{agm}", NULL, }, { FEXPR_AGMSequence, "AGMSequence", "\\operatorname{agm}", fexpr_write_latex_subscript_call, }, { FEXPR_Abs, "Abs", "", fexpr_write_latex_simple, }, { FEXPR_Acos, "Acos", "\\operatorname{acos}", NULL, }, { FEXPR_Acosh, "Acosh", "\\operatorname{acosh}", NULL, }, { FEXPR_Acot, "Acot", "\\operatorname{acot}", NULL, }, { FEXPR_Acoth, "Acoth", "\\operatorname{acoth}", NULL, }, { FEXPR_Acsc, "Acsc", "\\operatorname{acsc}", NULL, }, { FEXPR_Acsch, "Acsch", "\\operatorname{acsch}", NULL, }, { FEXPR_Add, "Add", "", fexpr_write_latex_add, }, { FEXPR_AiryAi, "AiryAi", "\\operatorname{Ai}", fexpr_write_latex_call1_optional_derivative, }, { FEXPR_AiryAiZero, "AiryAiZero", "a", fexpr_write_latex_subscript, }, { FEXPR_AiryBi, "AiryBi", "\\operatorname{Bi}", fexpr_write_latex_call1_optional_derivative, }, { FEXPR_AiryBiZero, "AiryBiZero", "b", fexpr_write_latex_subscript, }, { FEXPR_AlgebraicNumberSerialized, "AlgebraicNumberSerialized", "", fexpr_write_latex_misc_special, }, { FEXPR_AlgebraicNumbers, "AlgebraicNumbers", "\\overline{\\mathbb{Q}}", NULL, }, { FEXPR_All, "All", "", fexpr_write_latex_logic, }, { FEXPR_AnalyticContinuation, "AnalyticContinuation", "", fexpr_write_latex_misc_special, }, { FEXPR_And, "And", "", fexpr_write_latex_logic, }, { FEXPR_AngleBrackets, "AngleBrackets", "", fexpr_write_latex_simple, }, { FEXPR_Approximation, "Approximation", "", fexpr_write_latex_simple }, { FEXPR_Arg, "Arg", "\\arg", NULL, }, { FEXPR_ArgMax, "ArgMax", "", fexpr_write_latex_setop, }, { FEXPR_ArgMaxUnique, "ArgMaxUnique", "", fexpr_write_latex_setop, }, { FEXPR_ArgMin, "ArgMin", "", fexpr_write_latex_setop, }, { FEXPR_ArgMinUnique, "ArgMinUnique", "", fexpr_write_latex_setop, }, { FEXPR_Asec, "Asec", "\\operatorname{asec}", NULL, }, { FEXPR_Asech, "Asech", "\\operatorname{asech}", NULL, }, { FEXPR_Asin, "Asin", "\\operatorname{asin}", NULL, }, { FEXPR_Asinh, "Asinh", "\\operatorname{asinh}", NULL, }, { FEXPR_AsymptoticTo, "AsymptoticTo", "", fexpr_write_latex_misc_special, }, { FEXPR_Atan, "Atan", "\\operatorname{atan}", NULL, }, { FEXPR_Atan2, "Atan2", "\\operatorname{atan2}", NULL, }, { FEXPR_Atanh, "Atanh", "\\operatorname{atanh}", NULL, }, { FEXPR_BarnesG, "BarnesG", "G", NULL, }, { FEXPR_BellNumber, "BellNumber", "\\operatorname{B}", fexpr_write_latex_subscript, }, { FEXPR_BernoulliB, "BernoulliB", "B", fexpr_write_latex_subscript, }, { FEXPR_BernoulliPolynomial, "BernoulliPolynomial", "B", fexpr_write_latex_subscript_call, }, { FEXPR_BernsteinEllipse, "BernsteinEllipse", "\\mathcal{E}", fexpr_write_latex_subscript, }, { FEXPR_BesselI, "BesselI", "I", fexpr_write_latex_sub1_call1_optional_derivative, }, { FEXPR_BesselJ, "BesselJ", "J", fexpr_write_latex_sub1_call1_optional_derivative, }, { FEXPR_BesselJZero, "BesselJZero", "j", fexpr_write_latex_subscript, }, { FEXPR_BesselK, "BesselK", "K", fexpr_write_latex_sub1_call1_optional_derivative, }, { FEXPR_BesselY, "BesselY", "Y", fexpr_write_latex_sub1_call1_optional_derivative, }, { FEXPR_BesselYZero, "BesselYZero", "y", fexpr_write_latex_subscript, }, { FEXPR_BetaFunction, "BetaFunction", "\\mathrm{B}", NULL, }, { FEXPR_Binomial, "Binomial", "", fexpr_write_latex_simple2, }, { FEXPR_Braces, "Braces", "", fexpr_write_latex_simple, }, { FEXPR_Brackets, "Brackets", "", fexpr_write_latex_simple, }, { FEXPR_CC, "CC", "\\mathbb{C}", NULL, }, { FEXPR_Call, "Call", "", fexpr_write_latex_misc_special, }, { FEXPR_CallIndeterminate, "CallIndeterminate", "", fexpr_write_latex_misc_special, }, { FEXPR_Cardinality, "Cardinality", "", fexpr_write_latex_simple, }, { FEXPR_CarlsonHypergeometricR, "CarlsonHypergeometricR", "R", fexpr_write_latex_subscript_call, }, { FEXPR_CarlsonHypergeometricT, "CarlsonHypergeometricT", "T", fexpr_write_latex_subscript_call, }, { FEXPR_CarlsonRC, "CarlsonRC", "R_C", NULL, }, { FEXPR_CarlsonRD, "CarlsonRD", "R_D", NULL, }, { FEXPR_CarlsonRF, "CarlsonRF", "R_F", NULL, }, { FEXPR_CarlsonRG, "CarlsonRG", "R_G", NULL, }, { FEXPR_CarlsonRJ, "CarlsonRJ", "R_J", NULL, }, { FEXPR_CartesianPower, "CartesianPower", "", fexpr_write_latex_pow, }, { FEXPR_CartesianProduct, "CartesianProduct", "\\times", fexpr_write_latex_infix, }, { FEXPR_Case, "Case", "", NULL, }, { FEXPR_Cases, "Cases", "", fexpr_write_latex_cases, }, { FEXPR_CatalanConstant, "CatalanConstant", "G", NULL, }, { FEXPR_Ceil, "Ceil", "", fexpr_write_latex_simple, }, { FEXPR_Characteristic, "Characteristic", "\\operatorname{char}", NULL, }, { FEXPR_ChebyshevT, "ChebyshevT", "T", fexpr_write_latex_subscript_call, }, { FEXPR_ChebyshevU, "ChebyshevU", "U", fexpr_write_latex_subscript_call, }, { FEXPR_ClosedComplexDisk, "ClosedComplexDisk", "\\overline{D}", NULL, }, { FEXPR_ClosedOpenInterval, "ClosedOpenInterval", "", fexpr_write_latex_simple2_small, }, { FEXPR_Coefficient, "Coefficient", "", fexpr_write_latex_misc_special, }, { FEXPR_Column, "Column", "", NULL, }, { FEXPR_ColumnMatrix, "ColumnMatrix", "", fexpr_write_latex_matrix, }, { FEXPR_CommutativeRings, "CommutativeRings", "", NULL, }, { FEXPR_ComplexBranchDerivative, "ComplexBranchDerivative", "", fexpr_write_latex_derivative, }, { FEXPR_ComplexDerivative, "ComplexDerivative", "", fexpr_write_latex_derivative, }, { FEXPR_ComplexInfinities, "ComplexInfinities", "\\{\\hat{\\infty}, [e^{i \\theta}] \\infty\\}", NULL, }, { FEXPR_ComplexLimit, "ComplexLimit", "", fexpr_write_latex_limit, }, { FEXPR_ComplexSignedInfinities, "ComplexSignedInfinities", "\\{[e^{i \\theta}] \\infty\\}", NULL, }, { FEXPR_ComplexSingularityClosure, "ComplexSingularityClosure", "\\overline{\\mathbb{C}}_{\\text{Sing}}", NULL, }, { FEXPR_ComplexZeroMultiplicity, "ComplexZeroMultiplicity", "", fexpr_write_latex_residue, }, { FEXPR_Concatenation, "Concatenation", " \\,^\\frown ", fexpr_write_latex_infix, }, { FEXPR_CongruentMod, "CongruentMod", "", fexpr_write_latex_logic, }, { FEXPR_Conjugate, "Conjugate", "", fexpr_write_latex_simple, }, { FEXPR_ConreyGenerator, "ConreyGenerator", "g", fexpr_write_latex_subscript, }, { FEXPR_Cos, "Cos", "\\cos", NULL, }, { FEXPR_CosIntegral, "CosIntegral", "\\operatorname{Ci}", NULL, }, { FEXPR_Cosh, "Cosh", "\\cosh", NULL, }, { FEXPR_CoshIntegral, "CoshIntegral", "\\operatorname{Chi}", NULL, }, { FEXPR_Cot, "Cot", "\\cot", NULL, }, { FEXPR_Coth, "Coth", "\\coth", NULL, }, { FEXPR_CoulombC, "CoulombC", "C", fexpr_write_latex_subscript_call, }, { FEXPR_CoulombF, "CoulombF", "", fexpr_write_latex_misc_special, }, { FEXPR_CoulombG, "CoulombG", "", fexpr_write_latex_misc_special, }, { FEXPR_CoulombH, "CoulombH", "", fexpr_write_latex_misc_special, }, { FEXPR_CoulombSigma, "CoulombSigma", "\\sigma", fexpr_write_latex_subscript_call, }, { FEXPR_Csc, "Csc", "\\csc", NULL, }, { FEXPR_Csch, "Csch", "\\operatorname{csch}", NULL, }, { FEXPR_Csgn, "Csgn", "\\operatorname{csgn}", NULL, }, { FEXPR_CurvePath, "CurvePath", "", fexpr_write_latex_misc_special, }, { FEXPR_Cyclotomic, "Cyclotomic", "\\Phi", fexpr_write_latex_subscript_call, }, { FEXPR_Decimal, "Decimal", "", fexpr_write_latex_decimal, }, { FEXPR_DedekindEta, "DedekindEta", "\\eta", NULL, }, { FEXPR_DedekindEtaEpsilon, "DedekindEtaEpsilon", "\\varepsilon", NULL, }, { FEXPR_DedekindSum, "DedekindSum", "s", NULL, }, { FEXPR_Def, "Def", "", NULL, }, { FEXPR_Delta, "Delta", "\\Delta", NULL }, { FEXPR_Delta_, "Delta_", "\\Delta", fexpr_write_latex_subscript }, { FEXPR_Derivative, "Derivative", "", fexpr_write_latex_derivative, }, { FEXPR_Det, "Det", "\\operatorname{det}", NULL, }, { FEXPR_DiagonalMatrix, "DiagonalMatrix", "", fexpr_write_latex_matrix, }, { FEXPR_DigammaFunction, "DigammaFunction", "\\psi", fexpr_write_latex_call1_optional_derivative, }, { FEXPR_DigammaFunctionZero, "DigammaFunctionZero", "x", fexpr_write_latex_subscript, }, { FEXPR_DirichletCharacter, "DirichletCharacter", "", fexpr_write_latex_misc_special, }, { FEXPR_DirichletGroup, "DirichletGroup", "G", fexpr_write_latex_subscript, }, { FEXPR_DirichletL, "DirichletL", "L", NULL, }, { FEXPR_DirichletLZero, "DirichletLZero", "\\rho", fexpr_write_latex_subscript, }, { FEXPR_DirichletLambda, "DirichletLambda", "\\Lambda", NULL, }, { FEXPR_DiscreteLog, "DiscreteLog", "", fexpr_write_latex_misc_special, }, { FEXPR_Div, "Div", "", fexpr_write_latex_div, }, { FEXPR_Divides, "Divides", "\\mid", fexpr_write_latex_infix, }, { FEXPR_DivisorProduct, "DivisorProduct", "", fexpr_write_latex_divsum, }, { FEXPR_DivisorSigma, "DivisorSigma", "\\sigma", fexpr_write_latex_subscript_call, }, { FEXPR_DivisorSum, "DivisorSum", "", fexpr_write_latex_divsum, }, { FEXPR_DoubleFactorial, "DoubleFactorial", "", fexpr_write_latex_factorial, }, { FEXPR_EisensteinE, "EisensteinE", "E", fexpr_write_latex_subscript_call, }, { FEXPR_EisensteinG, "EisensteinG", "G", fexpr_write_latex_subscript_call, }, { FEXPR_Element, "Element", "\\in", fexpr_write_latex_infix, }, { FEXPR_Ellipsis, "Ellipsis", "\\ldots", NULL, }, { FEXPR_EllipticE, "EllipticE", "E", NULL, }, { FEXPR_EllipticK, "EllipticK", "K", NULL, }, { FEXPR_EllipticPi, "EllipticPi", "\\Pi", NULL, }, { FEXPR_EllipticRootE, "EllipticRootE", "e", fexpr_write_latex_subscript_call, }, { FEXPR_Enclosure, "Enclosure", "", fexpr_write_latex_simple }, { FEXPR_Equal, "Equal", "=", fexpr_write_latex_infix, }, { FEXPR_EqualAndElement, "EqualAndElement", "", fexpr_write_latex_misc_special, }, { FEXPR_EqualNearestDecimal, "EqualNearestDecimal", "", fexpr_write_latex_misc_special, }, { FEXPR_EqualQSeriesEllipsis, "EqualQSeriesEllipsis", "", fexpr_write_latex_misc_special, }, { FEXPR_Equivalent, "Equivalent", "", fexpr_write_latex_logic, }, { FEXPR_Erf, "Erf", "\\operatorname{erf}", NULL, }, { FEXPR_Erfc, "Erfc", "\\operatorname{erfc}", NULL, }, { FEXPR_Erfi, "Erfi", "\\operatorname{erfi}", NULL, }, { FEXPR_Euler, "Euler", "\\gamma", NULL, }, { FEXPR_EulerE, "EulerE", "E", fexpr_write_latex_subscript, }, { FEXPR_EulerPhi, "EulerPhi", "\\varphi", NULL, }, { FEXPR_EulerPolynomial, "EulerPolynomial", "E", fexpr_write_latex_subscript_call, }, { FEXPR_EulerQSeries, "EulerQSeries", "\\phi", NULL, }, { FEXPR_Exists, "Exists", "", fexpr_write_latex_logic, }, { FEXPR_Exp, "Exp", "\\exp", fexpr_write_latex_exp, }, { FEXPR_ExpIntegralE, "ExpIntegralE", "E", fexpr_write_latex_subscript_call, }, { FEXPR_ExpIntegralEi, "ExpIntegralEi", "\\operatorname{Ei}", NULL, }, { FEXPR_ExtendedRealNumbers, "ExtendedRealNumbers", "\\overline{\\mathbb{R}}", NULL, }, { FEXPR_Factorial, "Factorial", "", fexpr_write_latex_factorial, }, { FEXPR_FallingFactorial, "FallingFactorial", "", fexpr_write_latex_simple2, }, { FEXPR_False, "False", "\\operatorname{False}", NULL, }, { FEXPR_Fibonacci, "Fibonacci", "F", fexpr_write_latex_subscript, }, { FEXPR_Fields, "Fields", "", NULL, }, { FEXPR_FiniteField, "FiniteField", "", NULL, }, { FEXPR_Floor, "Floor", "", fexpr_write_latex_simple, }, { FEXPR_For, "For", "", NULL, }, { FEXPR_FormalLaurentSeries, "FormalLaurentSeries", "", fexpr_write_latex_alg_structure, }, { FEXPR_FormalPowerSeries, "FormalPowerSeries", "", fexpr_write_latex_alg_structure, }, { FEXPR_FormalPuiseuxSeries, "FormalPuiseuxSeries", "", fexpr_write_latex_alg_structure, }, { FEXPR_FresnelC, "FresnelC", "C", NULL, }, { FEXPR_FresnelS, "FresnelS", "S", NULL, }, { FEXPR_Fun, "Fun", "\\mapsto", fexpr_write_latex_infix, }, { FEXPR_GCD, "GCD", "\\gcd", NULL, }, { FEXPR_Gamma, "Gamma", "\\Gamma", NULL, }, { FEXPR_GaussLegendreWeight, "GaussLegendreWeight", "w", fexpr_write_latex_subscript, }, { FEXPR_GaussSum, "GaussSum", "G", fexpr_write_latex_subscript_call, }, { FEXPR_GegenbauerC, "GegenbauerC", "", NULL, }, { FEXPR_GeneralLinearGroup, "GeneralLinearGroup", "\\operatorname{GL}", fexpr_write_latex_subscript_call, }, { FEXPR_GeneralizedBernoulliB, "GeneralizedBernoulliB", "B", fexpr_write_latex_subscript, }, { FEXPR_GeneralizedRiemannHypothesis, "GeneralizedRiemannHypothesis", "\\operatorname{GRH}", NULL, }, { FEXPR_GlaisherConstant, "GlaisherConstant", "A", NULL, }, { FEXPR_GoldenRatio, "GoldenRatio", "\\varphi", NULL, }, { FEXPR_Greater, "Greater", ">", fexpr_write_latex_infix, }, { FEXPR_GreaterEqual, "GreaterEqual", "\\ge", fexpr_write_latex_infix, }, { FEXPR_GreekGamma, "GreekGamma", "\\Gamma", NULL }, { FEXPR_GreekGamma_, "GreekGamma_", "\\Gamma", fexpr_write_latex_subscript }, { FEXPR_GreekPi, "GreekPi", "\\Pi", NULL }, { FEXPR_GreekPi_, "GreekPi_", "\\Pi", fexpr_write_latex_subscript }, { FEXPR_Guess, "Guess", "", fexpr_write_latex_simple }, { FEXPR_HankelH1, "HankelH1", "H^{(1)}", fexpr_write_latex_subscript_call, }, { FEXPR_HankelH2, "HankelH2", "H^{(2)}", fexpr_write_latex_subscript_call, }, { FEXPR_HarmonicNumber, "HarmonicNumber", "H", fexpr_write_latex_subscript, }, { FEXPR_HermiteH, "HermiteH", "H", fexpr_write_latex_subscript_call, }, { FEXPR_HilbertClassPolynomial, "HilbertClassPolynomial", "H", fexpr_write_latex_subscript_call, }, { FEXPR_HilbertMatrix, "HilbertMatrix", "H", fexpr_write_latex_subscript, }, { FEXPR_HurwitzZeta, "HurwitzZeta", "\\zeta", fexpr_write_latex_call2_optional_derivative, }, { FEXPR_Hypergeometric0F1, "Hypergeometric0F1", "\\,{}_0F_1", NULL, }, { FEXPR_Hypergeometric0F1Regularized, "Hypergeometric0F1Regularized", "\\,{}_0{\\textbf F}_1", NULL, }, { FEXPR_Hypergeometric1F1, "Hypergeometric1F1", "\\,{}_1F_1", NULL, }, { FEXPR_Hypergeometric1F1Regularized, "Hypergeometric1F1Regularized", "\\,{}_1{\\textbf F}_1", NULL, }, { FEXPR_Hypergeometric1F2, "Hypergeometric1F2", "\\,{}_1F_2", NULL, }, { FEXPR_Hypergeometric1F2Regularized, "Hypergeometric1F2Regularized", "\\,{}_1{\\textbf F}_2", NULL, }, { FEXPR_Hypergeometric2F0, "Hypergeometric2F0", "\\,{}_2F_0", NULL, }, { FEXPR_Hypergeometric2F1, "Hypergeometric2F1", "\\,{}_2F_1", NULL, }, { FEXPR_Hypergeometric2F1Regularized, "Hypergeometric2F1Regularized", "\\,{}_2{\\textbf F}_1", NULL, }, { FEXPR_Hypergeometric2F2, "Hypergeometric2F2", "\\,{}_2F_2", NULL, }, { FEXPR_Hypergeometric2F2Regularized, "Hypergeometric2F2Regularized", "\\,{}_2{\\textbf F}_2", NULL, }, { FEXPR_Hypergeometric3F2, "Hypergeometric3F2", "\\,{}_3F_2", NULL, }, { FEXPR_Hypergeometric3F2Regularized, "Hypergeometric3F2Regularized", "\\,{}_3{\\textbf F}_2", NULL, }, { FEXPR_HypergeometricU, "HypergeometricU", "U", NULL, }, { FEXPR_HypergeometricUStar, "HypergeometricUStar", "U^{*}", NULL, }, { FEXPR_HypergeometricUStarRemainder, "HypergeometricUStarRemainder", "R", fexpr_write_latex_subscript_call, }, { FEXPR_IdentityMatrix, "IdentityMatrix", "I", fexpr_write_latex_subscript, }, { FEXPR_Im, "Im", "\\operatorname{Im}", NULL, }, { FEXPR_Implies, "Implies", "", fexpr_write_latex_logic, }, { FEXPR_IncompleteBeta, "IncompleteBeta", "\\mathrm{B}", fexpr_write_latex_subscript_call, }, { FEXPR_IncompleteBetaRegularized, "IncompleteBetaRegularized", "I", fexpr_write_latex_subscript_call, }, { FEXPR_IncompleteEllipticE, "IncompleteEllipticE", "E", NULL, }, { FEXPR_IncompleteEllipticF, "IncompleteEllipticF", "F", NULL, }, { FEXPR_IncompleteEllipticPi, "IncompleteEllipticPi", "\\Pi", NULL, }, { FEXPR_IndefiniteIntegralEqual, "IndefiniteIntegralEqual", "", fexpr_write_latex_misc_special, }, { FEXPR_Infimum, "Infimum", "", fexpr_write_latex_setop, }, { FEXPR_Infinity, "Infinity", "\\infty", NULL, }, { FEXPR_IntegersGreaterEqual, "IntegersGreaterEqual", "", fexpr_write_latex_range, }, { FEXPR_IntegersLessEqual, "IntegersLessEqual", "", fexpr_write_latex_range, }, { FEXPR_Integral, "Integral", "", fexpr_write_latex_integral, }, { FEXPR_Intersection, "Intersection", "\\cap", fexpr_write_latex_infix, }, { FEXPR_Interval, "Interval", "", fexpr_write_latex_simple2_small, }, { FEXPR_IsEven, "IsEven", "", fexpr_write_latex_simple, }, { FEXPR_IsHolomorphicOn, "IsHolomorphicOn", "", fexpr_write_latex_misc_special, }, { FEXPR_IsMeromorphicOn, "IsMeromorphicOn", "", fexpr_write_latex_misc_special, }, { FEXPR_IsOdd, "IsOdd", "", fexpr_write_latex_simple, }, { FEXPR_IsPrime, "IsPrime", "", fexpr_write_latex_simple, }, { FEXPR_Item, "Item", "", fexpr_write_latex_simple2, }, { FEXPR_JacobiP, "JacobiP", "", NULL, }, { FEXPR_JacobiSymbol, "JacobiSymbol", "", fexpr_write_latex_simple2, }, { FEXPR_JacobiTheta, "JacobiTheta", "\\theta", fexpr_write_latex_sub1_call2_optional_derivative, }, { FEXPR_JacobiThetaEpsilon, "JacobiThetaEpsilon", "\\varepsilon", fexpr_write_latex_subscript_call, }, { FEXPR_JacobiThetaPermutation, "JacobiThetaPermutation", "S", fexpr_write_latex_subscript_call, }, { FEXPR_JacobiThetaQ, "JacobiThetaQ", "\\theta", fexpr_write_latex_sub1_call2_optional_derivative, }, { FEXPR_KeiperLiLambda, "KeiperLiLambda", "\\lambda", fexpr_write_latex_subscript, }, { FEXPR_KhinchinConstant, "KhinchinConstant", "K", NULL, }, { FEXPR_KroneckerDelta, "KroneckerDelta", "", fexpr_write_latex_simple2_small, }, { FEXPR_KroneckerSymbol, "KroneckerSymbol", "", fexpr_write_latex_simple2, }, { FEXPR_LCM, "LCM", "\\operatorname{lcm}", NULL, }, { FEXPR_LaguerreL, "LaguerreL", "", NULL, }, { FEXPR_LambertW, "LambertW", "W", fexpr_write_latex_misc_special, }, { FEXPR_Lamda, "Lamda", "\\Lambda", NULL }, { FEXPR_Lamda_, "Lamda_", "\\Lambda", fexpr_write_latex_subscript }, { FEXPR_LandauG, "LandauG", "g", NULL, }, { FEXPR_Lattice, "Lattice", "", fexpr_write_latex_collection }, { FEXPR_LeftLimit, "LeftLimit", "", fexpr_write_latex_limit, }, { FEXPR_LegendreP, "LegendreP", "P", fexpr_write_latex_subscript_call, }, { FEXPR_LegendrePolynomialZero, "LegendrePolynomialZero", "x", fexpr_write_latex_subscript, }, { FEXPR_LegendreSymbol, "LegendreSymbol", "", fexpr_write_latex_simple2, }, { FEXPR_Length, "Length", "", fexpr_write_latex_simple, }, { FEXPR_LerchPhi, "LerchPhi", "\\Phi", NULL, }, { FEXPR_Less, "Less", "<", fexpr_write_latex_infix, }, { FEXPR_LessEqual, "LessEqual", "\\le", fexpr_write_latex_infix, }, { FEXPR_Limit, "Limit", "", fexpr_write_latex_limit, }, { FEXPR_LiouvilleLambda, "LiouvilleLambda", "\\lambda", NULL, }, { FEXPR_List, "List", "", fexpr_write_latex_collection, }, { FEXPR_Log, "Log", "\\log", NULL, }, { FEXPR_LogBarnesG, "LogBarnesG", "\\log G", NULL, }, { FEXPR_LogBarnesGRemainder, "LogBarnesGRemainder", "R", fexpr_write_latex_subscript_call, }, { FEXPR_LogGamma, "LogGamma", "\\log \\Gamma", NULL, }, { FEXPR_LogIntegral, "LogIntegral", "\\operatorname{li}", NULL, }, { FEXPR_Logic, "Logic", "", fexpr_write_latex_logic }, { FEXPR_LowerGamma, "LowerGamma", "\\gamma", NULL, }, { FEXPR_Matrices, "Matrices", "", fexpr_write_latex_misc_special, }, { FEXPR_Matrix, "Matrix", "", fexpr_write_latex_matrix, }, { FEXPR_Matrix2x2, "Matrix2x2", "", fexpr_write_latex_matrix, }, { FEXPR_Max, "Max", "\\max", NULL, }, { FEXPR_Maximum, "Maximum", "", fexpr_write_latex_setop, }, { FEXPR_MeromorphicDerivative, "MeromorphicDerivative", "", fexpr_write_latex_derivative, }, { FEXPR_MeromorphicLimit, "MeromorphicLimit", "", fexpr_write_latex_limit, }, { FEXPR_Min, "Min", "\\min", NULL, }, { FEXPR_Minimum, "Minimum", "", fexpr_write_latex_setop, }, { FEXPR_Mod, "Mod", "\\bmod", fexpr_write_latex_infix, }, { FEXPR_ModularGroupAction, "ModularGroupAction", "\\circ", fexpr_write_latex_infix, }, { FEXPR_ModularGroupFundamentalDomain, "ModularGroupFundamentalDomain", "\\mathcal{F}", NULL, }, { FEXPR_ModularJ, "ModularJ", "j", NULL, }, { FEXPR_ModularLambda, "ModularLambda", "\\lambda", NULL, }, { FEXPR_ModularLambdaFundamentalDomain, "ModularLambdaFundamentalDomain", "\\mathcal{F}_{\\lambda}", NULL, }, { FEXPR_MoebiusMu, "MoebiusMu", "\\mu", NULL, }, { FEXPR_Mul, "Mul", "", fexpr_write_latex_mul, }, { FEXPR_MultiZetaValue, "MultiZetaValue", "\\zeta", NULL, }, { FEXPR_NN, "NN", "\\mathbb{N}", NULL, }, { FEXPR_Neg, "Neg", "", fexpr_write_latex_neg_pos, }, { FEXPR_Not, "Not", "", fexpr_write_latex_logic, }, { FEXPR_NotElement, "NotElement", "\\notin", fexpr_write_latex_infix, }, { FEXPR_NotEqual, "NotEqual", "\\ne", fexpr_write_latex_infix, }, { FEXPR_NumberE, "NumberE", "e", NULL, }, { FEXPR_NumberI, "NumberI", "i", NULL, }, { FEXPR_Omega, "Omega", "\\Omega", NULL }, { FEXPR_Omega_, "Omega_", "\\Omega", fexpr_write_latex_subscript }, { FEXPR_One, "One", "1", fexpr_write_latex_subscript, }, { FEXPR_OpenClosedInterval, "OpenClosedInterval", "", fexpr_write_latex_simple2_small, }, { FEXPR_OpenComplexDisk, "OpenComplexDisk", "D", NULL, }, { FEXPR_OpenInterval, "OpenInterval", "", fexpr_write_latex_simple2_small, }, { FEXPR_OpenRealBall, "OpenRealBall", "", fexpr_write_latex_simple2_small, }, { FEXPR_Or, "Or", "", fexpr_write_latex_logic, }, { FEXPR_Otherwise, "Otherwise", "", NULL, }, { FEXPR_PSL2Z, "PSL2Z", "\\operatorname{PSL}_2(\\mathbb{Z})", NULL, }, { FEXPR_Parentheses, "Parentheses", "", fexpr_write_latex_simple, }, { FEXPR_PartitionsP, "PartitionsP", "p", NULL, }, { FEXPR_Path, "Path", "\\rightsquigarrow", fexpr_write_latex_infix, }, { FEXPR_Phi, "Phi", "\\Phi", NULL }, { FEXPR_Phi_, "Phi_", "\\Phi", fexpr_write_latex_subscript }, { FEXPR_Pi, "Pi", "\\pi", NULL, }, { FEXPR_Pol, "Pol", "", NULL, }, { FEXPR_Poles, "Poles", "", fexpr_write_latex_setop, }, { FEXPR_PolyLog, "PolyLog", "\\operatorname{Li}", fexpr_write_latex_subscript_call, }, { FEXPR_Polynomial, "Polynomial", "", fexpr_write_latex_misc_special, }, { FEXPR_PolynomialDegree, "PolynomialDegree", "\\deg", NULL, }, { FEXPR_PolynomialFractions, "PolynomialFractions", "", fexpr_write_latex_alg_structure, }, { FEXPR_PolynomialRootIndexed, "PolynomialRootIndexed", "", fexpr_write_latex_misc_special, }, { FEXPR_PolynomialRootNearest, "PolynomialRootNearest", "", fexpr_write_latex_misc_special, }, { FEXPR_Polynomials, "Polynomials", "", fexpr_write_latex_alg_structure, }, { FEXPR_Pos, "Pos", "", fexpr_write_latex_neg_pos, }, { FEXPR_Pow, "Pow", "", fexpr_write_latex_pow, }, { FEXPR_Prime, "Prime", "p", fexpr_write_latex_subscript, }, { FEXPR_PrimePi, "PrimePi", "\\pi", NULL, }, { FEXPR_PrimeProduct, "PrimeProduct", "", fexpr_write_latex_divsum, }, { FEXPR_PrimeSum, "PrimeSum", "", fexpr_write_latex_divsum, }, { FEXPR_Primes, "Primes", "\\mathbb{P}", NULL, }, { FEXPR_PrimitiveDirichletCharacters, "PrimitiveDirichletCharacters", "G^{\\text{Primitive}}", fexpr_write_latex_subscript, }, { FEXPR_PrimitiveReducedPositiveIntegralBinaryQuadraticForms, "PrimitiveReducedPositiveIntegralBinaryQuadraticForms", "\\mathcal{Q}^{*}", fexpr_write_latex_subscript_call, }, { FEXPR_Product, "Product", "", fexpr_write_latex_sum_product, }, { FEXPR_ProjectiveComplexNumbers, "ProjectiveComplexNumbers", "\\hat{\\mathbb{C}}_{\\infty}", NULL, }, { FEXPR_ProjectiveRealNumbers, "ProjectiveRealNumbers", "\\hat{\\mathbb{R}}_{\\infty}", NULL, }, { FEXPR_Psi, "Psi", "\\Psi", NULL }, { FEXPR_Psi_, "Psi_", "\\Psi", fexpr_write_latex_subscript }, { FEXPR_QQ, "QQ", "\\mathbb{Q}", NULL, }, { FEXPR_QSeriesCoefficient, "QSeriesCoefficient", "", fexpr_write_latex_misc_special, }, { FEXPR_QuotientRing, "QuotientRing", "", NULL, }, { FEXPR_RR, "RR", "\\mathbb{R}", NULL, }, { FEXPR_Range, "Range", "", fexpr_write_latex_range, }, { FEXPR_Re, "Re", "\\operatorname{Re}", NULL, }, { FEXPR_RealAbs, "RealAbs", "", fexpr_write_latex_simple, }, { FEXPR_RealAlgebraicNumbers, "RealAlgebraicNumbers", "\\overline{\\mathbb{Q}}_{\\mathbb{R}}", NULL, }, { FEXPR_RealBall, "RealBall", "", fexpr_write_latex_simple2_small, }, { FEXPR_RealDerivative, "RealDerivative", "", fexpr_write_latex_derivative, }, { FEXPR_RealInfinities, "RealInfinities", "\\{\\hat{\\infty}, \\pm \\infty\\}", NULL, }, { FEXPR_RealLimit, "RealLimit", "", fexpr_write_latex_limit, }, { FEXPR_RealSignedInfinities, "RealSignedInfinities", "\\{\\pm \\infty\\}", NULL, }, { FEXPR_RealSingularityClosure, "RealSingularityClosure", "\\overline{\\mathbb{R}}_{\\text{Sing}}", NULL, }, { FEXPR_Repeat, "Repeat", "", fexpr_write_latex_misc_special, }, { FEXPR_Residue, "Residue", "", fexpr_write_latex_residue, }, { FEXPR_RiemannHypothesis, "RiemannHypothesis", "\\operatorname{RH}", NULL, }, { FEXPR_RiemannXi, "RiemannXi", "\\xi", NULL, }, { FEXPR_RiemannZeta, "RiemannZeta", "\\zeta", fexpr_write_latex_call1_optional_derivative, }, { FEXPR_RiemannZetaZero, "RiemannZetaZero", "\\rho", fexpr_write_latex_subscript, }, { FEXPR_RightLimit, "RightLimit", "", fexpr_write_latex_limit, }, { FEXPR_Rings, "Rings", "", NULL, }, { FEXPR_RisingFactorial, "RisingFactorial", "", fexpr_write_latex_simple2, }, { FEXPR_Root, "Root", "", NULL, }, { FEXPR_RootOfUnity, "RootOfUnity", "\\zeta", fexpr_write_latex_subscript, }, { FEXPR_Row, "Row", "", NULL, }, { FEXPR_RowMatrix, "RowMatrix", "", fexpr_write_latex_matrix, }, { FEXPR_SL2Z, "SL2Z", "\\operatorname{SL}_2(\\mathbb{Z})", NULL, }, { FEXPR_Same, "Same", "=", fexpr_write_latex_infix, }, { FEXPR_Sec, "Sec", "\\sec", NULL, }, { FEXPR_Sech, "Sech", "\\operatorname{sech}", NULL, }, { FEXPR_SequenceLimit, "SequenceLimit", "", fexpr_write_latex_limit, }, { FEXPR_SequenceLimitInferior, "SequenceLimitInferior", "", fexpr_write_latex_limit, }, { FEXPR_SequenceLimitSuperior, "SequenceLimitSuperior", "", fexpr_write_latex_limit, }, { FEXPR_Ser, "Ser", "", NULL, }, { FEXPR_Set, "Set", "", fexpr_write_latex_collection, }, { FEXPR_SetMinus, "SetMinus", "\\setminus", fexpr_write_latex_infix, }, { FEXPR_Sets, "Sets", "", NULL, }, { FEXPR_ShowExpandedNormalForm, "ShowExpandedNormalForm", "", fexpr_write_latex_show_form, }, { FEXPR_Sigma, "Sigma", "\\Sigma", NULL }, { FEXPR_Sigma_, "Sigma_", "\\Sigma", fexpr_write_latex_subscript }, { FEXPR_Sign, "Sign", "\\operatorname{sgn}", NULL, }, { FEXPR_SignExtendedComplexNumbers, "SignExtendedComplexNumbers", "\\overline{\\mathbb{C}}_{[e^{i \\theta}] \\infty}", NULL, }, { FEXPR_Sin, "Sin", "\\sin", NULL, }, { FEXPR_SinIntegral, "SinIntegral", "\\operatorname{Si}", NULL, }, { FEXPR_Sinc, "Sinc", "\\operatorname{sinc}", NULL, }, { FEXPR_SingularValues, "SingularValues", "\\sigma", NULL, }, { FEXPR_Sinh, "Sinh", "\\sinh", NULL, }, { FEXPR_SinhIntegral, "SinhIntegral", "\\operatorname{Shi}", NULL, }, { FEXPR_SloaneA, "SloaneA", "", fexpr_write_latex_misc_special, }, { FEXPR_Solutions, "Solutions", "", fexpr_write_latex_setop, }, { FEXPR_SpecialLinearGroup, "SpecialLinearGroup", "\\operatorname{SL}", fexpr_write_latex_subscript_call, }, { FEXPR_Spectrum, "Spectrum", "\\operatorname{spec}", NULL, }, { FEXPR_SphericalHarmonicY, "SphericalHarmonicY", "", NULL, }, { FEXPR_Sqrt, "Sqrt", "", fexpr_write_latex_simple, }, { FEXPR_SquaresR, "SquaresR", "r", fexpr_write_latex_subscript_call, }, { FEXPR_Step, "Step", "", fexpr_write_latex_collection, }, { FEXPR_StieltjesGamma, "StieltjesGamma", "\\gamma", fexpr_write_latex_subscript_call, }, { FEXPR_StirlingCycle, "StirlingCycle", "", fexpr_write_latex_simple2, }, { FEXPR_StirlingS1, "StirlingS1", "", fexpr_write_latex_simple2, }, { FEXPR_StirlingS2, "StirlingS2", "", fexpr_write_latex_simple2, }, { FEXPR_StirlingSeriesRemainder, "StirlingSeriesRemainder", "R", fexpr_write_latex_subscript_call, }, { FEXPR_Sub, "Sub", "", fexpr_write_latex_sub, }, { FEXPR_Subscript, "Subscript", "", fexpr_write_latex_simple2, }, { FEXPR_Subset, "Subset", "\\subset", fexpr_write_latex_infix, }, { FEXPR_SubsetEqual, "SubsetEqual", "\\subseteq", fexpr_write_latex_infix, }, { FEXPR_Subsets, "Subsets", "\\mathscr{P}", NULL, }, { FEXPR_Sum, "Sum", "", fexpr_write_latex_sum_product, }, { FEXPR_Supremum, "Supremum", "", fexpr_write_latex_setop, }, { FEXPR_SymmetricPolynomial, "SymmetricPolynomial", "e", fexpr_write_latex_subscript_call, }, { FEXPR_Tan, "Tan", "\\tan", NULL, }, { FEXPR_Tanh, "Tanh", "\\tanh", NULL, }, { FEXPR_Theta, "Theta", "\\Theta", NULL }, { FEXPR_Theta_, "Theta_", "\\Theta", fexpr_write_latex_subscript }, { FEXPR_True, "True", "\\operatorname{True}", NULL, }, { FEXPR_Tuple, "Tuple", "", fexpr_write_latex_collection, }, { FEXPR_Tuples, "Tuples", "", NULL, }, { FEXPR_Undefined, "Undefined", "\\mathfrak{u}", NULL, }, { FEXPR_Union, "Union", "\\cup", fexpr_write_latex_infix, }, { FEXPR_UniqueSolution, "UniqueSolution", "", fexpr_write_latex_setop, }, { FEXPR_UniqueZero, "UniqueZero", "", fexpr_write_latex_setop, }, { FEXPR_UnitCircle, "UnitCircle", "\\mathbb{T}", NULL, }, { FEXPR_Unknown, "Unknown", "\\operatorname{Unknown}", NULL, }, { FEXPR_UnsignedInfinity, "UnsignedInfinity", "\\hat{\\infty}", NULL, }, { FEXPR_UpperGamma, "UpperGamma", "\\Gamma", NULL, }, { FEXPR_UpperHalfPlane, "UpperHalfPlane", "\\mathbb{H}", NULL, }, { FEXPR_WeierstrassP, "WeierstrassP", "\\wp", NULL, }, { FEXPR_WeierstrassSigma, "WeierstrassSigma", "\\sigma", NULL, }, { FEXPR_WeierstrassZeta, "WeierstrassZeta", "\\zeta", NULL, }, { FEXPR_Where, "Where", "", fexpr_write_latex_where, }, { FEXPR_XGCD, "XGCD", "\\operatorname{xgcd}", NULL, }, { FEXPR_XX, "XX", "\\text{x}", fexpr_write_latex_subscript, }, { FEXPR_Xi, "Xi", "\\Xi", NULL }, { FEXPR_Xi_, "Xi_", "\\Xi", fexpr_write_latex_subscript }, { FEXPR_ZZ, "ZZ", "\\mathbb{Z}", NULL, }, { FEXPR_Zero, "Zero", "0", fexpr_write_latex_subscript, }, { FEXPR_ZeroMatrix, "ZeroMatrix", "0", fexpr_write_latex_subscript, }, { FEXPR_Zeros, "Zeros", "", fexpr_write_latex_setop, }, { FEXPR_alpha, "alpha", "\\alpha", NULL }, { FEXPR_alpha_, "alpha_", "\\alpha", fexpr_write_latex_subscript }, { FEXPR_beta, "beta", "\\beta", NULL }, { FEXPR_beta_, "beta_", "\\beta", fexpr_write_latex_subscript }, { FEXPR_chi, "chi", "\\chi", NULL }, { FEXPR_chi_, "chi_", "\\chi", fexpr_write_latex_subscript }, { FEXPR_delta, "delta", "\\delta", NULL }, { FEXPR_delta_, "delta_", "\\delta", fexpr_write_latex_subscript }, { FEXPR_ell, "ell", "\\ell", NULL }, { FEXPR_ell_, "ell_", "\\ell", fexpr_write_latex_subscript }, { FEXPR_epsilon, "epsilon", "\\varepsilon", NULL }, { FEXPR_epsilon_, "epsilon_", "\\varepsilon", fexpr_write_latex_subscript }, { FEXPR_eta, "eta", "\\eta", NULL }, { FEXPR_eta_, "eta_", "\\eta", fexpr_write_latex_subscript }, { FEXPR_gamma, "gamma", "\\gamma", NULL }, { FEXPR_gamma_, "gamma_", "\\gamma", fexpr_write_latex_subscript }, { FEXPR_iota, "iota", "\\iota", NULL }, { FEXPR_iota_, "iota_", "\\iota", fexpr_write_latex_subscript }, { FEXPR_kappa, "kappa", "\\kappa", NULL }, { FEXPR_kappa_, "kappa_", "\\kappa", fexpr_write_latex_subscript }, { FEXPR_lamda, "lamda", "\\lambda", NULL }, { FEXPR_lamda_, "lamda_", "\\lambda", fexpr_write_latex_subscript }, { FEXPR_mu, "mu", "\\mu", NULL }, { FEXPR_mu_, "mu_", "\\mu", fexpr_write_latex_subscript }, { FEXPR_nu, "nu", "\\nu", NULL }, { FEXPR_nu_, "nu_", "\\nu", fexpr_write_latex_subscript }, { FEXPR_omega, "omega", "\\omega", NULL }, { FEXPR_omega_, "omega_", "\\omega", fexpr_write_latex_subscript }, { FEXPR_phi, "phi", "\\phi", NULL }, { FEXPR_phi_, "phi_", "\\phi", fexpr_write_latex_subscript }, { FEXPR_pi, "pi", "\\pi", NULL }, { FEXPR_pi_, "pi_", "\\pi", fexpr_write_latex_subscript }, { FEXPR_rho, "rho", "\\rho", NULL }, { FEXPR_rho_, "rho_", "\\rho", fexpr_write_latex_subscript }, { FEXPR_sigma, "sigma", "\\sigma", NULL }, { FEXPR_sigma_, "sigma_", "\\sigma", fexpr_write_latex_subscript }, { FEXPR_tau, "tau", "\\tau", NULL }, { FEXPR_tau_, "tau_", "\\tau", fexpr_write_latex_subscript }, { FEXPR_theta, "theta", "\\theta", NULL }, { FEXPR_theta_, "theta_", "\\theta", fexpr_write_latex_subscript }, { FEXPR_varphi, "varphi", "\\varphi", NULL }, { FEXPR_varphi_, "varphi_", "\\varphi", fexpr_write_latex_subscript }, { FEXPR_vartheta, "vartheta", "\\vartheta", NULL }, { FEXPR_vartheta_, "vartheta_", "\\vartheta", fexpr_write_latex_subscript }, { FEXPR_xi, "xi", "\\xi", NULL }, { FEXPR_xi_, "xi_", "\\xi", fexpr_write_latex_subscript }, { FEXPR_zeta, "zeta", "\\zeta", NULL }, { FEXPR_zeta_, "zeta_", "\\zeta", fexpr_write_latex_subscript }, }; calcium-0.4.1/fmpz_mpoly_q.h000066400000000000000000000233431407704557200160360ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef FMPZ_MPOLY_Q_H #define FMPZ_MPOLY_Q_H #ifdef FMPZ_MPOLY_Q_INLINES_C #define FMPZ_MPOLY_Q_INLINE #else #define FMPZ_MPOLY_Q_INLINE static __inline__ #endif #ifdef __cplusplus extern "C" { #endif #include "flint/fmpz_mpoly.h" #include "flint/fmpq.h" #include "acb.h" #include "calcium.h" typedef struct { fmpz_mpoly_struct num; fmpz_mpoly_struct den; } fmpz_mpoly_q_struct; typedef fmpz_mpoly_q_struct fmpz_mpoly_q_t[1]; #define fmpz_mpoly_q_numref(x) (&((x)->num)) #define fmpz_mpoly_q_denref(x) (&((x)->den)) /* Memory management */ void fmpz_mpoly_q_init(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_clear(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx); /* Assignment */ void fmpz_mpoly_q_swap(fmpz_mpoly_q_t x, fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_set(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_set_fmpq(fmpz_mpoly_q_t res, const fmpq_t x, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_set_fmpz(fmpz_mpoly_q_t res, const fmpz_t x, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_set_si(fmpz_mpoly_q_t res, slong x, const fmpz_mpoly_ctx_t ctx); /* Canonicalisation */ void fmpz_mpoly_q_canonicalise(fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx); int fmpz_mpoly_q_is_canonical(const fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx); /* Properties */ FMPZ_MPOLY_Q_INLINE int fmpz_mpoly_q_is_zero(const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) { return fmpz_mpoly_is_zero(fmpz_mpoly_q_numref(x), ctx); } FMPZ_MPOLY_Q_INLINE int fmpz_mpoly_q_is_one(const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) { return fmpz_mpoly_is_one(fmpz_mpoly_q_numref(x), ctx) && fmpz_mpoly_is_one(fmpz_mpoly_q_denref(x), ctx); } FMPZ_MPOLY_Q_INLINE int fmpz_mpoly_q_is_fmpz(const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) { return fmpz_mpoly_is_fmpz(fmpz_mpoly_q_numref(x), ctx) && fmpz_mpoly_is_one(fmpz_mpoly_q_denref(x), ctx); } FMPZ_MPOLY_Q_INLINE int fmpz_mpoly_q_is_fmpq(const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) { return fmpz_mpoly_is_fmpz(fmpz_mpoly_q_numref(x), ctx) && fmpz_mpoly_is_fmpz(fmpz_mpoly_q_denref(x), ctx); } void fmpz_mpoly_q_used_vars(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_used_vars_num(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_used_vars_den(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx); /* Special values */ FMPZ_MPOLY_Q_INLINE void fmpz_mpoly_q_zero(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_zero(fmpz_mpoly_q_numref(res), ctx); fmpz_mpoly_one(fmpz_mpoly_q_denref(res), ctx); } FMPZ_MPOLY_Q_INLINE void fmpz_mpoly_q_one(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_one(fmpz_mpoly_q_numref(res), ctx); fmpz_mpoly_one(fmpz_mpoly_q_denref(res), ctx); } FMPZ_MPOLY_Q_INLINE void fmpz_mpoly_q_gen(fmpz_mpoly_q_t res, slong i, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_gen(fmpz_mpoly_q_numref(res), i, ctx); fmpz_mpoly_one(fmpz_mpoly_q_denref(res), ctx); } /* Input and output */ void fmpz_mpoly_q_print_pretty(const fmpz_mpoly_q_t f, const char ** x, const fmpz_mpoly_ctx_t ctx); /* Random generation */ void fmpz_mpoly_q_randtest(fmpz_mpoly_q_t res, flint_rand_t state, slong length, mp_limb_t coeff_bits, slong exp_bound, const fmpz_mpoly_ctx_t ctx); /* Comparisons */ int fmpz_mpoly_q_equal(const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx); /* Arithmetic */ void fmpz_mpoly_q_neg(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_add(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_sub(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_mul(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_div(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_inv(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx); void _fmpz_mpoly_q_add(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_mpoly_t y_num, const fmpz_mpoly_t y_den, const fmpz_mpoly_ctx_t ctx); void _fmpz_mpoly_q_sub(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_mpoly_t y_num, const fmpz_mpoly_t y_den, const fmpz_mpoly_ctx_t ctx); void _fmpz_mpoly_q_mul(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_mpoly_t y_num, const fmpz_mpoly_t y_den, const fmpz_mpoly_ctx_t ctx); void _fmpz_mpoly_q_div(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_mpoly_t y_num, const fmpz_mpoly_t y_den, const fmpz_mpoly_ctx_t ctx); void _fmpz_mpoly_q_add_fmpq(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_t y_num, const fmpz_t y_den, const fmpz_mpoly_ctx_t ctx); void _fmpz_mpoly_q_sub_fmpq(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_t y_num, const fmpz_t y_den, const fmpz_mpoly_ctx_t ctx); void _fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_t y_num, const fmpz_t y_den, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_add_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_add_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_sub_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_sub_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_mul_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_div_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_q_div_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx); FMPZ_MPOLY_Q_INLINE void fmpz_mpoly_q_add_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong c, const fmpz_mpoly_ctx_t ctx) { fmpz_t t; fmpz_init_set_si(t, c); fmpz_mpoly_q_add_fmpz(res, x, t, ctx); fmpz_clear(t); } FMPZ_MPOLY_Q_INLINE void fmpz_mpoly_q_sub_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong c, const fmpz_mpoly_ctx_t ctx) { fmpz_t t; fmpz_init_set_si(t, c); fmpz_mpoly_q_sub_fmpz(res, x, t, ctx); fmpz_clear(t); } FMPZ_MPOLY_Q_INLINE void fmpz_mpoly_q_mul_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong c, const fmpz_mpoly_ctx_t ctx) { fmpz_t t; fmpz_init_set_si(t, c); fmpz_mpoly_q_mul_fmpz(res, x, t, ctx); fmpz_clear(t); } FMPZ_MPOLY_Q_INLINE void fmpz_mpoly_q_div_si(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, slong c, const fmpz_mpoly_ctx_t ctx) { fmpz_t t; fmpz_init_set_si(t, c); fmpz_mpoly_q_div_fmpz(res, x, t, ctx); fmpz_clear(t); } /* Polynomial helper functions */ FMPZ_MPOLY_Q_INLINE void _fmpz_vec_content2(fmpz_t res, const fmpz * vec, slong len, const fmpz_t inp) { if (fmpz_is_pm1(inp)) { fmpz_one(res); } else { slong i; fmpz_abs(res, inp); for (i = len - 1; i >= 0; i--) { fmpz_gcd(res, res, vec + i); if (fmpz_is_one(res)) break; } } } FMPZ_MPOLY_Q_INLINE void fmpz_mpoly_gcd_assert_successful(fmpz_mpoly_t res, const fmpz_mpoly_t x, const fmpz_mpoly_t y, const fmpz_mpoly_ctx_t ctx) { if (!fmpz_mpoly_gcd(res, x, y, ctx)) { flint_printf("fmpz_mpoly_gcd failed\n"); flint_abort(); } } FMPZ_MPOLY_Q_INLINE void _fmpz_mpoly_q_mpoly_divexact(fmpz_mpoly_t res, const fmpz_mpoly_t x, const fmpz_mpoly_t y, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_fmpz(y, ctx)) fmpz_mpoly_scalar_divexact_fmpz(res, x, y->coeffs, ctx); else fmpz_mpoly_div(res, x, y, ctx); } /* Content */ FMPZ_MPOLY_Q_INLINE void _fmpz_mpoly_q_content(fmpz_t num, fmpz_t den, const fmpz_mpoly_t xnum, const fmpz_mpoly_t xden, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_zero(xnum, ctx)) { fmpz_one(num); fmpz_one(den); } else { _fmpz_vec_content(den, xden->coeffs, xden->length); _fmpz_vec_content(num, xnum->coeffs, xnum->length); } } FMPZ_MPOLY_Q_INLINE void fmpz_mpoly_q_content(fmpq_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) { _fmpz_mpoly_q_content(fmpq_numref(res), fmpq_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), ctx); } /* Evaluation */ void fmpz_mpoly_q_evaluate_acb(acb_t res, const fmpz_mpoly_q_t f, acb_srcptr x, slong prec, const fmpz_mpoly_ctx_t ctx); #ifdef __cplusplus } #endif #endif calcium-0.4.1/fmpz_mpoly_q/000077500000000000000000000000001407704557200156605ustar00rootroot00000000000000calcium-0.4.1/fmpz_mpoly_q/add.c000066400000000000000000000243001407704557200165530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" static void _fmpz_mpoly_q_add_fmpz_mpoly_den(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_mpoly_t y_num, const fmpz_t y_den, const fmpz_mpoly_ctx_t ctx) { fmpz_t g; fmpz_init(g); if (fmpz_mpoly_is_fmpz(y_num, ctx)) { if (res_num == x_num || res_num == y_num) { fmpz_t t, u; fmpz_init_set(t, y_num->coeffs); fmpz_init_set(u, y_den); _fmpz_mpoly_q_add_fmpq(res_num, res_den, x_num, x_den, t, u, ctx); fmpz_clear(t); fmpz_clear(u); } else { _fmpz_mpoly_q_add_fmpq(res_num, res_den, x_num, x_den, y_num->coeffs, y_den, ctx); } return; } if (fmpz_mpoly_is_fmpz(x_den, ctx)) { fmpz_gcd(g, x_den->coeffs, y_den); if (fmpz_is_one(g)) { fmpz_mpoly_t t, u; fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); /* todo: avoid one alloc? not helpful right now because fmpz_mpoly_add does not work inplace */ fmpz_mpoly_scalar_mul_fmpz(t, y_num, x_den->coeffs, ctx); fmpz_mpoly_scalar_mul_fmpz(u, x_num, y_den, ctx); fmpz_mpoly_add(res_num, t, u, ctx); fmpz_mul(g, x_den->coeffs, y_den); fmpz_mpoly_set_fmpz(res_den, g, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } else { fmpz_t a, b; fmpz_mpoly_t t, u; fmpz_init(a); fmpz_init(b); fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); fmpz_divexact(a, y_den, g); fmpz_divexact(b, x_den->coeffs, g); fmpz_mpoly_scalar_mul_fmpz(t, y_num, b, ctx); fmpz_mpoly_scalar_mul_fmpz(u, x_num, a, ctx); fmpz_mpoly_add(res_num, t, u, ctx); if (fmpz_mpoly_is_zero(res_num, ctx)) fmpz_one(a); else _fmpz_vec_content2(a, res_num->coeffs, res_num->length, g); if (fmpz_is_one(a)) { fmpz_mul(g, b, y_den); fmpz_mpoly_set_fmpz(res_den, g, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_num, res_num, a, ctx); fmpz_divexact(g, y_den, a); fmpz_mul(g, g, b); fmpz_mpoly_set_fmpz(res_den, g, ctx); } fmpz_clear(a); fmpz_clear(b); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } } else { _fmpz_vec_content2(g, x_den->coeffs, x_den->length, y_den); if (fmpz_is_one(g)) { fmpz_mpoly_t t, u; fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); /* todo: avoid one alloc? not helpful right now because fmpz_mpoly_add does not work inplace */ fmpz_mpoly_mul(t, y_num, x_den, ctx); fmpz_mpoly_scalar_mul_fmpz(u, x_num, y_den, ctx); fmpz_mpoly_add(res_num, t, u, ctx); fmpz_set(g, y_den); fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, g, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } else { fmpz_t a; fmpz_mpoly_t b, t, u; fmpz_init(a); fmpz_mpoly_init(b, ctx); fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); fmpz_divexact(a, y_den, g); fmpz_mpoly_scalar_divexact_fmpz(b, x_den, g, ctx); fmpz_mpoly_mul(t, y_num, b, ctx); fmpz_mpoly_scalar_mul_fmpz(u, x_num, a, ctx); fmpz_mpoly_add(res_num, t, u, ctx); if (fmpz_mpoly_is_zero(res_num, ctx)) fmpz_one(a); else _fmpz_vec_content2(a, res_num->coeffs, res_num->length, g); if (fmpz_is_one(a)) { fmpz_set(g, y_den); fmpz_mpoly_scalar_mul_fmpz(res_den, b, g, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_num, res_num, a, ctx); fmpz_divexact(g, y_den, a); fmpz_mpoly_scalar_mul_fmpz(res_den, b, g, ctx); } fmpz_clear(a); fmpz_mpoly_clear(b, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } } fmpz_clear(g); } void _fmpz_mpoly_q_add(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_mpoly_t y_num, const fmpz_mpoly_t y_den, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_zero(x_num, ctx)) { fmpz_mpoly_set(res_num, y_num, ctx); fmpz_mpoly_set(res_den, y_den, ctx); return; } if (fmpz_mpoly_is_zero(y_num, ctx)) { fmpz_mpoly_set(res_num, x_num, ctx); fmpz_mpoly_set(res_den, x_den, ctx); return; } if (fmpz_mpoly_equal(x_den, y_den, ctx)) { fmpz_mpoly_add(res_num, x_num, y_num, ctx); if (fmpz_mpoly_is_one(x_den, ctx) || fmpz_mpoly_is_zero(res_num, ctx)) { fmpz_mpoly_one(res_den, ctx); } else if (fmpz_mpoly_is_fmpz(x_den, ctx)) { fmpz_t t; fmpz_init(t); _fmpz_vec_content2(t, res_num->coeffs, res_num->length, x_den->coeffs); if (fmpz_is_one(t)) { fmpz_mpoly_set(res_den, x_den, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_num, res_num, t, ctx); fmpz_mpoly_scalar_divexact_fmpz(res_den, x_den, t, ctx); } fmpz_clear(t); } else { fmpz_mpoly_t t; fmpz_mpoly_init(t, ctx); fmpz_mpoly_gcd_assert_successful(t, res_num, x_den, ctx); if (fmpz_mpoly_is_one(t, ctx)) { fmpz_mpoly_set(res_den, x_den, ctx); } else { _fmpz_mpoly_q_mpoly_divexact(res_num, res_num, t, ctx); _fmpz_mpoly_q_mpoly_divexact(res_den, x_den, t, ctx); } fmpz_mpoly_clear(t, ctx); } return; } if (fmpz_mpoly_is_one(x_den, ctx)) { if (res_num == y_num) { fmpz_mpoly_t t; fmpz_mpoly_init(t, ctx); fmpz_mpoly_mul(t, x_num, y_den, ctx); fmpz_mpoly_add(res_num, t, y_num, ctx); fmpz_mpoly_clear(t, ctx); } else { fmpz_mpoly_mul(res_num, x_num, y_den, ctx); fmpz_mpoly_add(res_num, res_num, y_num, ctx); } fmpz_mpoly_set(res_den, y_den, ctx); return; } if (fmpz_mpoly_is_one(y_den, ctx)) { if (res_num == x_num) { fmpz_mpoly_t t; fmpz_mpoly_init(t, ctx); fmpz_mpoly_mul(t, y_num, x_den, ctx); fmpz_mpoly_add(res_num, x_num, t, ctx); fmpz_mpoly_clear(t, ctx); } else { fmpz_mpoly_mul(res_num, y_num, x_den, ctx); fmpz_mpoly_add(res_num, x_num, res_num, ctx); } fmpz_mpoly_set(res_den, x_den, ctx); return; } if (fmpz_mpoly_is_fmpz(y_den, ctx)) { _fmpz_mpoly_q_add_fmpz_mpoly_den(res_num, res_den, x_num, x_den, y_num, y_den->coeffs, ctx); return; } if (fmpz_mpoly_is_fmpz(x_den, ctx)) { _fmpz_mpoly_q_add_fmpz_mpoly_den(res_num, res_den, y_num, y_den, x_num, x_den->coeffs, ctx); return; } { fmpz_mpoly_t g; fmpz_mpoly_init(g, ctx); fmpz_mpoly_gcd_assert_successful(g, x_den, y_den, ctx); if (fmpz_mpoly_is_one(g, ctx)) { fmpz_mpoly_t t, u; fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); /* todo: avoid one alloc? not helpful right now because fmpz_mpoly_add does not work inplace */ fmpz_mpoly_mul(t, x_num, y_den, ctx); fmpz_mpoly_mul(u, y_num, x_den, ctx); fmpz_mpoly_add(res_num, t, u, ctx); fmpz_mpoly_mul(res_den, x_den, y_den, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } else { fmpz_mpoly_t a, b, t, u; fmpz_mpoly_init(a, ctx); fmpz_mpoly_init(b, ctx); fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); _fmpz_mpoly_q_mpoly_divexact(a, x_den, g, ctx); _fmpz_mpoly_q_mpoly_divexact(b, y_den, g, ctx); fmpz_mpoly_mul(t, x_num, b, ctx); fmpz_mpoly_mul(u, y_num, a, ctx); fmpz_mpoly_add(res_num, t, u, ctx); fmpz_mpoly_gcd_assert_successful(t, res_num, g, ctx); if (fmpz_mpoly_is_one(t, ctx)) { fmpz_mpoly_mul(res_den, x_den, b, ctx); } else { _fmpz_mpoly_q_mpoly_divexact(res_num, res_num, t, ctx); _fmpz_mpoly_q_mpoly_divexact(g, x_den, t, ctx); fmpz_mpoly_mul(res_den, g, b, ctx); } fmpz_mpoly_clear(a, ctx); fmpz_mpoly_clear(b, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } fmpz_mpoly_clear(g, ctx); } } void fmpz_mpoly_q_add(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) { _fmpz_mpoly_q_add(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), fmpz_mpoly_q_numref(y), fmpz_mpoly_q_denref(y), ctx); } calcium-0.4.1/fmpz_mpoly_q/add_fmpq.c000066400000000000000000000107561407704557200176100ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void _fmpz_mpoly_q_add_fmpq(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_t y_num, const fmpz_t y_den, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_zero(x_num, ctx)) { fmpz_mpoly_set_fmpz(res_num, y_num, ctx); fmpz_mpoly_set_fmpz(res_den, y_den, ctx); return; } if (fmpz_is_zero(y_num)) { fmpz_mpoly_set(res_num, x_num, ctx); fmpz_mpoly_set(res_den, x_den, ctx); return; } /* todo: special-case integer x_den */ if (fmpz_mpoly_equal_fmpz(x_den, y_den, ctx)) { fmpz_mpoly_add_fmpz(res_num, x_num, y_num, ctx); if (fmpz_is_one(y_den)) { fmpz_mpoly_one(res_den, ctx); } else { fmpz_t t; fmpz_init(t); _fmpz_vec_content2(t, res_num->coeffs, res_num->length, y_den); if (fmpz_is_one(t)) { fmpz_mpoly_set(res_den, x_den, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_num, res_num, t, ctx); fmpz_divexact(t, y_den, t); fmpz_mpoly_set_fmpz(res_den, t, ctx); } fmpz_clear(t); } return; } if (fmpz_mpoly_is_one(x_den, ctx)) { fmpz_mpoly_scalar_mul_fmpz(res_num, x_num, y_den, ctx); fmpz_mpoly_add_fmpz(res_num, res_num, y_num, ctx); fmpz_mpoly_set_fmpz(res_den, y_den, ctx); return; } if (fmpz_is_one(y_den)) { if (res_num == x_num) { fmpz_mpoly_t t; fmpz_mpoly_init(t, ctx); fmpz_mpoly_scalar_mul_fmpz(t, x_den, y_num, ctx); fmpz_mpoly_add(res_num, x_num, t, ctx); fmpz_mpoly_clear(t, ctx); } else { fmpz_mpoly_scalar_mul_fmpz(res_num, x_den, y_num, ctx); fmpz_mpoly_add(res_num, x_num, res_num, ctx); } fmpz_mpoly_set(res_den, x_den, ctx); return; } { fmpz_t g; fmpz_init(g); _fmpz_vec_content2(g, x_den->coeffs, x_den->length, y_den); if (fmpz_is_one(g)) { fmpz_mpoly_t t, u; fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); fmpz_mpoly_scalar_mul_fmpz(t, x_num, y_den, ctx); /* todo: avoid one alloc? */ fmpz_mpoly_scalar_mul_fmpz(u, x_den, y_num, ctx); fmpz_mpoly_add(res_num, t, u, ctx); fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, y_den, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } else { fmpz_mpoly_t t, u; fmpz_t b, c; fmpz_init(b); fmpz_init(c); fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); fmpz_mpoly_scalar_divexact_fmpz(u, x_den, g, ctx); fmpz_divexact(b, y_den, g); fmpz_mpoly_scalar_mul_fmpz(t, x_num, b, ctx); fmpz_mpoly_scalar_mul_fmpz(u, u, y_num, ctx); fmpz_mpoly_add(res_num, t, u, ctx); _fmpz_vec_content2(c, res_num->coeffs, res_num->length, g); if (fmpz_is_one(c)) { fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, b, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_num, res_num, c, ctx); fmpz_mpoly_scalar_divexact_fmpz(res_den, x_den, c, ctx); fmpz_mpoly_scalar_mul_fmpz(res_den, res_den, b, ctx); } fmpz_clear(b); fmpz_clear(c); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } fmpz_clear(g); } } void fmpz_mpoly_q_add_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) { _fmpz_mpoly_q_add_fmpq(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), fmpq_numref(y), fmpq_denref(y), ctx); } calcium-0.4.1/fmpz_mpoly_q/add_fmpz.c000066400000000000000000000013621407704557200176120ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_add_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) { fmpz_t one; *one = 1; _fmpz_mpoly_q_add_fmpq(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), y, one, ctx); } calcium-0.4.1/fmpz_mpoly_q/canonicalise.c000066400000000000000000000050371407704557200204610ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_canonicalise(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_one(fmpz_mpoly_q_denref(res), ctx)) { return; } else if (fmpz_mpoly_is_zero(fmpz_mpoly_q_numref(res), ctx)) { fmpz_mpoly_one(fmpz_mpoly_q_denref(res), ctx); return; } else if (fmpz_mpoly_is_fmpz(fmpz_mpoly_q_denref(res), ctx)) { fmpz_t g; fmpz_init(g); _fmpz_vec_content(g, fmpz_mpoly_q_numref(res)->coeffs, fmpz_mpoly_q_numref(res)->length); fmpz_gcd(g, g, fmpz_mpoly_q_denref(res)->coeffs); if (fmpz_sgn(fmpz_mpoly_q_denref(res)->coeffs) < 0) fmpz_neg(g, g); if (!fmpz_is_one(g)) { fmpz_mpoly_scalar_divexact_fmpz(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_numref(res), g, ctx); fmpz_divexact(fmpz_mpoly_q_denref(res)->coeffs, fmpz_mpoly_q_denref(res)->coeffs, g); } fmpz_clear(g); } else if (fmpz_mpoly_is_fmpz(fmpz_mpoly_q_numref(res), ctx)) { fmpz_t g; fmpz_init(g); _fmpz_vec_content(g, fmpz_mpoly_q_denref(res)->coeffs, fmpz_mpoly_q_denref(res)->length); fmpz_gcd(g, g, fmpz_mpoly_q_numref(res)->coeffs); if (fmpz_sgn(fmpz_mpoly_q_denref(res)->coeffs) < 0) fmpz_neg(g, g); if (!fmpz_is_one(g)) { fmpz_mpoly_scalar_divexact_fmpz(fmpz_mpoly_q_denref(res), fmpz_mpoly_q_denref(res), g, ctx); fmpz_divexact(fmpz_mpoly_q_numref(res)->coeffs, fmpz_mpoly_q_numref(res)->coeffs, g); } fmpz_clear(g); } else { fmpz_mpoly_t g; fmpz_mpoly_init(g, ctx); fmpz_mpoly_gcd_assert_successful(g, fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), ctx); if (fmpz_sgn(fmpz_mpoly_q_denref(res)->coeffs) < 0) fmpz_mpoly_neg(g, g, ctx); if (!fmpz_mpoly_is_one(g, ctx)) { _fmpz_mpoly_q_mpoly_divexact(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_numref(res), g, ctx); _fmpz_mpoly_q_mpoly_divexact(fmpz_mpoly_q_denref(res), fmpz_mpoly_q_denref(res), g, ctx); } fmpz_mpoly_clear(g, ctx); } } calcium-0.4.1/fmpz_mpoly_q/clear.c000066400000000000000000000011261407704557200171120ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_clear(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_clear(fmpz_mpoly_q_numref(res), ctx); fmpz_mpoly_clear(fmpz_mpoly_q_denref(res), ctx); } calcium-0.4.1/fmpz_mpoly_q/div.c000066400000000000000000000035731407704557200166160ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void _fmpz_mpoly_q_div(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_mpoly_t y_num, const fmpz_mpoly_t y_den, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_zero(y_num, ctx)) { flint_printf("_fmpz_mpoly_q_div: division by zero\n"); flint_abort(); } if (fmpz_mpoly_is_zero(x_num, ctx) || fmpz_mpoly_is_zero(y_num, ctx)) { fmpz_mpoly_zero(res_num, ctx); fmpz_mpoly_one(res_den, ctx); return; } if (res_num == y_num) { fmpz_mpoly_t t, u; fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); _fmpz_mpoly_q_mul(t, u, x_num, x_den, y_den, y_num, ctx); fmpz_mpoly_swap(res_num, t, ctx); fmpz_mpoly_swap(res_den, u, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } else { _fmpz_mpoly_q_mul(res_num, res_den, x_num, x_den, y_den, y_num, ctx); } if (fmpz_sgn(res_den->coeffs) < 0) { fmpz_mpoly_neg(res_num, res_num, ctx); fmpz_mpoly_neg(res_den, res_den, ctx); } } void fmpz_mpoly_q_div(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) { _fmpz_mpoly_q_div(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), fmpz_mpoly_q_numref(y), fmpz_mpoly_q_denref(y), ctx); } calcium-0.4.1/fmpz_mpoly_q/div_fmpq.c000066400000000000000000000026611407704557200176360ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_div_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) { if (fmpq_is_zero(y)) { flint_printf("fmpz_mpoly_q_div_fmpq: division by zero\n"); flint_abort(); } else { if (fmpz_sgn(fmpq_numref(y)) > 0) { _fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), fmpq_denref(y), fmpq_numref(y), ctx); } else { fmpz_t t, u; fmpz_init(t); fmpz_init(u); fmpz_neg(t, fmpq_numref(y)); fmpz_neg(u, fmpq_denref(y)); _fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), u, t, ctx); fmpz_clear(t); fmpz_clear(u); } } } calcium-0.4.1/fmpz_mpoly_q/div_fmpz.c000066400000000000000000000025761407704557200176540ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_div_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) { if (fmpz_is_zero(y)) { flint_printf("fmpz_mpoly_q_div_fmpz: division by zero\n"); flint_abort(); } else { if (fmpz_sgn(y) > 0) { fmpz_t one; *one = 1; _fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), one, y, ctx); } else { fmpz_t t; fmpz_t one; *one = -1; fmpz_init(t); fmpz_neg(t, y); _fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), one, t, ctx); fmpz_clear(t); } } } calcium-0.4.1/fmpz_mpoly_q/equal.c000066400000000000000000000012561407704557200171370ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int fmpz_mpoly_q_equal(const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) { return fmpz_mpoly_equal(fmpz_mpoly_q_numref(x), fmpz_mpoly_q_numref(y), ctx) && fmpz_mpoly_equal(fmpz_mpoly_q_denref(x), fmpz_mpoly_q_denref(y), ctx); } calcium-0.4.1/fmpz_mpoly_q/evaluate_acb.c000066400000000000000000000044161407704557200204440ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" /* stupid algorithm, just to have something working... */ void fmpz_mpoly_evaluate_acb(acb_t res, const fmpz_mpoly_t pol, acb_srcptr x, slong prec, const fmpz_mpoly_ctx_t ctx) { slong i, j, len, nvars; acb_t s, t, u; ulong * exp; /* todo: support fmpz exponents */ len = fmpz_mpoly_length(pol, ctx); if (len == 0) { acb_zero(res); return; } if (len == 1 && fmpz_mpoly_is_fmpz(pol, ctx)) { acb_set_round_fmpz(res, pol->coeffs, prec); return; } nvars = ctx->minfo->nvars; exp = flint_malloc(sizeof(ulong) * nvars); acb_init(s); acb_init(t); acb_init(u); for (i = 0; i < len; i++) { fmpz_mpoly_get_term_exp_ui(exp, pol, i, ctx); acb_one(t); for (j = 0; j < nvars; j++) { if (exp[j] == 1) { acb_mul(t, t, x + j, prec); } else if (exp[j] >= 2) { acb_pow_ui(u, x + j, exp[j], prec); acb_mul(t, t, u, prec); } } acb_addmul_fmpz(s, t, pol->coeffs + i, prec); } acb_swap(res, s); flint_free(exp); acb_clear(s); acb_clear(t); acb_clear(u); } void fmpz_mpoly_q_evaluate_acb(acb_t res, const fmpz_mpoly_q_t f, acb_srcptr x, slong prec, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_one(fmpz_mpoly_q_denref(f), ctx)) { fmpz_mpoly_evaluate_acb(res, fmpz_mpoly_q_numref(f), x, prec, ctx); } else { acb_t t; acb_init(t); fmpz_mpoly_evaluate_acb(t, fmpz_mpoly_q_denref(f), x, prec, ctx); if (acb_contains_zero(t)) { acb_indeterminate(res); } else { fmpz_mpoly_evaluate_acb(res, fmpz_mpoly_q_numref(f), x, prec, ctx); acb_div(res, res, t, prec); } acb_clear(t); } } calcium-0.4.1/fmpz_mpoly_q/init.c000066400000000000000000000012061407704557200167660ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_init(fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_init(fmpz_mpoly_q_numref(res), ctx); fmpz_mpoly_init(fmpz_mpoly_q_denref(res), ctx); fmpz_mpoly_one(fmpz_mpoly_q_denref(res), ctx); } calcium-0.4.1/fmpz_mpoly_q/inlines.c000066400000000000000000000006761407704557200174760ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #define FMPZ_MPOLY_Q_INLINES_C #include "fmpz_mpoly_q.h" calcium-0.4.1/fmpz_mpoly_q/inv.c000066400000000000000000000020141407704557200166150ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_inv(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_zero(fmpz_mpoly_q_numref(x), ctx)) { flint_printf("fmpz_mpoly_q_inv: division by zero\n"); flint_abort(); } if (res != x) fmpz_mpoly_q_set(res, x, ctx); fmpz_mpoly_swap(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), ctx); if (fmpz_sgn(fmpz_mpoly_q_denref(res)->coeffs) < 0) { fmpz_mpoly_neg(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_numref(res), ctx); fmpz_mpoly_neg(fmpz_mpoly_q_denref(res), fmpz_mpoly_q_denref(res), ctx); } } calcium-0.4.1/fmpz_mpoly_q/is_canonical.c000066400000000000000000000021261407704557200204470ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int fmpz_mpoly_q_is_canonical(const fmpz_mpoly_q_t res, const fmpz_mpoly_ctx_t ctx) { if (!fmpz_mpoly_is_canonical(fmpz_mpoly_q_numref(res), ctx)) return 0; if (!fmpz_mpoly_is_canonical(fmpz_mpoly_q_denref(res), ctx)) return 0; if (fmpz_mpoly_is_zero(fmpz_mpoly_q_denref(res), ctx)) return 0; if (fmpz_sgn(fmpz_mpoly_q_denref(res)->coeffs) < 0) return 0; { int ans; fmpz_mpoly_t g; fmpz_mpoly_init(g, ctx); fmpz_mpoly_gcd_assert_successful(g, fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), ctx); ans = fmpz_mpoly_is_one(g, ctx); fmpz_mpoly_clear(g, ctx); return ans; } } calcium-0.4.1/fmpz_mpoly_q/mul.c000066400000000000000000000107601407704557200166250ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void _fmpz_mpoly_q_mul(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_mpoly_t y_num, const fmpz_mpoly_t y_den, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_zero(x_num, ctx) || fmpz_mpoly_is_zero(y_num, ctx)) { fmpz_mpoly_zero(res_num, ctx); fmpz_mpoly_one(res_den, ctx); return; } if (fmpz_mpoly_equal(x_den, y_den, ctx)) { fmpz_mpoly_mul(res_num, x_num, y_num, ctx); fmpz_mpoly_mul(res_den, x_den, y_den, ctx); return; } /* todo: special-case integer denominators; scalar multiplication */ if (fmpz_mpoly_is_one(x_den, ctx)) { fmpz_mpoly_t t, u; fmpz_mpoly_init(t, ctx); fmpz_mpoly_gcd_assert_successful(t, x_num, y_den, ctx); if (fmpz_mpoly_is_one(t, ctx)) { fmpz_mpoly_mul(res_num, x_num, y_num, ctx); fmpz_mpoly_mul(res_den, x_den, y_den, ctx); } else { fmpz_mpoly_init(u, ctx); _fmpz_mpoly_q_mpoly_divexact(u, x_num, t, ctx); fmpz_mpoly_mul(res_num, u, y_num, ctx); _fmpz_mpoly_q_mpoly_divexact(u, y_den, t, ctx); fmpz_mpoly_mul(res_den, x_den, u, ctx); fmpz_mpoly_clear(u, ctx); } fmpz_mpoly_clear(t, ctx); return; } if (fmpz_mpoly_is_one(y_den, ctx)) { fmpz_mpoly_t t, u; fmpz_mpoly_init(t, ctx); fmpz_mpoly_gcd_assert_successful(t, y_num, x_den, ctx); if (fmpz_mpoly_is_one(t, ctx)) { fmpz_mpoly_mul(res_num, x_num, y_num, ctx); fmpz_mpoly_mul(res_den, x_den, y_den, ctx); } else { fmpz_mpoly_init(u, ctx); _fmpz_mpoly_q_mpoly_divexact(u, y_num, t, ctx); fmpz_mpoly_mul(res_num, u, x_num, ctx); _fmpz_mpoly_q_mpoly_divexact(u, x_den, t, ctx); fmpz_mpoly_mul(res_den, y_den, u, ctx); fmpz_mpoly_clear(u, ctx); } fmpz_mpoly_clear(t, ctx); return; } { fmpz_mpoly_t t, u, x, y; fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); fmpz_mpoly_init(x, ctx); fmpz_mpoly_init(y, ctx); fmpz_mpoly_gcd_assert_successful(t, x_num, y_den, ctx); if (fmpz_mpoly_is_one(t, ctx)) { fmpz_mpoly_gcd_assert_successful(u, x_den, y_num, ctx); if (fmpz_mpoly_is_one(u, ctx)) { fmpz_mpoly_mul(res_num, x_num, y_num, ctx); fmpz_mpoly_mul(res_den, x_den, y_den, ctx); } else { fmpz_mpoly_div(y, y_num, u, ctx); fmpz_mpoly_mul(res_num, x_num, y, ctx); fmpz_mpoly_div(x, x_den, u, ctx); fmpz_mpoly_mul(res_den, x, y_den, ctx); } } else { fmpz_mpoly_gcd_assert_successful(u, x_den, y_num, ctx); if (fmpz_mpoly_is_one(u, ctx)) { fmpz_mpoly_div(x, x_num, t, ctx); fmpz_mpoly_mul(res_num, x, y_num, ctx); fmpz_mpoly_div(y, y_den, t, ctx); fmpz_mpoly_mul(res_den, x_den, y, ctx); } else { fmpz_mpoly_div(x, x_num, t, ctx); fmpz_mpoly_div(y, y_num, u, ctx); fmpz_mpoly_mul(res_num, x, y, ctx); fmpz_mpoly_div(x, x_den, u, ctx); fmpz_mpoly_div(y, y_den, t, ctx); fmpz_mpoly_mul(res_den, x, y, ctx); } } fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); fmpz_mpoly_clear(x, ctx); fmpz_mpoly_clear(y, ctx); } } void fmpz_mpoly_q_mul(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) { _fmpz_mpoly_q_mul(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), fmpz_mpoly_q_numref(y), fmpz_mpoly_q_denref(y), ctx); } calcium-0.4.1/fmpz_mpoly_q/mul_fmpq.c000066400000000000000000000103761407704557200176530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void _fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_t y_num, const fmpz_t y_den, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_zero(x_num, ctx) || fmpz_is_zero(y_num)) { fmpz_mpoly_zero(res_num, ctx); fmpz_mpoly_one(res_den, ctx); return; } if (fmpz_mpoly_equal_fmpz(x_den, y_den, ctx)) { fmpz_mpoly_scalar_mul_fmpz(res_num, x_num, y_num, ctx); fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, y_den, ctx); return; } if (fmpz_mpoly_is_one(x_den, ctx)) { fmpz_t t; fmpz_init(t); _fmpz_vec_content2(t, x_num->coeffs, x_num->length, y_den); if (fmpz_is_one(t)) { fmpz_mpoly_scalar_mul_fmpz(res_num, x_num, y_num, ctx); fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, y_den, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_num, x_num, t, ctx); fmpz_mpoly_scalar_mul_fmpz(res_num, res_num, y_num, ctx); fmpz_divexact(t, y_den, t); fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, t, ctx); } fmpz_clear(t); return; } if (fmpz_is_one(y_den)) { fmpz_t t; fmpz_init(t); _fmpz_vec_content2(t, x_den->coeffs, x_den->length, y_num); if (fmpz_is_one(t)) { fmpz_mpoly_scalar_mul_fmpz(res_num, x_num, y_num, ctx); fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, y_den, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_den, x_den, t, ctx); fmpz_mpoly_scalar_mul_fmpz(res_den, res_den, y_den, ctx); fmpz_divexact(t, y_num, t); fmpz_mpoly_scalar_mul_fmpz(res_num, x_num, t, ctx); } fmpz_clear(t); return; } { fmpz_t t, u; fmpz_init(t); fmpz_init(u); _fmpz_vec_content2(t, x_num->coeffs, x_num->length, y_den); _fmpz_vec_content2(u, x_den->coeffs, x_den->length, y_num); if (fmpz_is_one(t)) { if (fmpz_is_one(u)) { fmpz_mpoly_scalar_mul_fmpz(res_num, x_num, y_num, ctx); fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, y_den, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_den, x_den, u, ctx); fmpz_mpoly_scalar_mul_fmpz(res_den, res_den, y_den, ctx); fmpz_divexact(u, y_num, u); fmpz_mpoly_scalar_mul_fmpz(res_num, x_num, u, ctx); } } else { if (fmpz_is_one(u)) { fmpz_mpoly_scalar_divexact_fmpz(res_num, x_num, t, ctx); fmpz_mpoly_scalar_mul_fmpz(res_num, res_num, y_num, ctx); fmpz_divexact(t, y_den, t); fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, t, ctx); } else { fmpz_t v; fmpz_init(v); fmpz_mpoly_scalar_divexact_fmpz(res_num, x_num, t, ctx); fmpz_divexact(v, y_num, u); fmpz_mpoly_scalar_mul_fmpz(res_num, res_num, v, ctx); fmpz_mpoly_scalar_divexact_fmpz(res_den, x_den, u, ctx); fmpz_divexact(v, y_den, t); fmpz_mpoly_scalar_mul_fmpz(res_den, res_den, v, ctx); fmpz_clear(v); } } fmpz_clear(t); fmpz_clear(u); } } void fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) { _fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), fmpq_numref(y), fmpq_denref(y), ctx); } calcium-0.4.1/fmpz_mpoly_q/mul_fmpz.c000066400000000000000000000013621407704557200176570ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_mul_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) { fmpz_t one; *one = 1; _fmpz_mpoly_q_mul_fmpq(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), y, one, ctx); } calcium-0.4.1/fmpz_mpoly_q/neg.c000066400000000000000000000012301407704557200165710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_neg(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_neg(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_numref(x), ctx); fmpz_mpoly_set(fmpz_mpoly_q_denref(res), fmpz_mpoly_q_denref(x), ctx); } calcium-0.4.1/fmpz_mpoly_q/print_pretty.c000066400000000000000000000021721407704557200205710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_print_pretty(const fmpz_mpoly_q_t f, const char ** x, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_one(fmpz_mpoly_q_denref(f), ctx)) { fmpz_mpoly_print_pretty(fmpz_mpoly_q_numref(f), x, ctx); } else if (fmpz_mpoly_is_fmpz(fmpz_mpoly_q_denref(f), ctx)) { flint_printf("("); fmpz_mpoly_print_pretty(fmpz_mpoly_q_numref(f), x, ctx); flint_printf(")/"); fmpz_mpoly_print_pretty(fmpz_mpoly_q_denref(f), x, ctx); } else { flint_printf("("); fmpz_mpoly_print_pretty(fmpz_mpoly_q_numref(f), x, ctx); flint_printf(")/("); fmpz_mpoly_print_pretty(fmpz_mpoly_q_denref(f), x, ctx); flint_printf(")"); } } calcium-0.4.1/fmpz_mpoly_q/randtest.c000066400000000000000000000022701407704557200176510ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_randtest(fmpz_mpoly_q_t res, flint_rand_t state, slong length, mp_limb_t coeff_bits, slong exp_bound, const fmpz_mpoly_ctx_t ctx) { length = n_randint(state, length + 1); fmpz_mpoly_randtest_bound(fmpz_mpoly_q_numref(res), state, length, coeff_bits, exp_bound, ctx); if (n_randint(state, 2)) { fmpz_mpoly_one(fmpz_mpoly_q_denref(res), ctx); } else { if (n_randint(state, 2)) { length = 1; exp_bound = 1; } fmpz_mpoly_randtest_bound(fmpz_mpoly_q_denref(res), state, length, coeff_bits, exp_bound, ctx); if (fmpz_mpoly_is_zero(fmpz_mpoly_q_denref(res), ctx)) fmpz_mpoly_one(fmpz_mpoly_q_denref(res), ctx); } fmpz_mpoly_q_canonicalise(res, ctx); } calcium-0.4.1/fmpz_mpoly_q/set.c000066400000000000000000000012761407704557200166250ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_set(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_ctx_t ctx) { if (res != x) { fmpz_mpoly_set(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_numref(x), ctx); fmpz_mpoly_set(fmpz_mpoly_q_denref(res), fmpz_mpoly_q_denref(x), ctx); } } calcium-0.4.1/fmpz_mpoly_q/set_fmpq.c000066400000000000000000000012171407704557200176430ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_set_fmpq(fmpz_mpoly_q_t res, const fmpq_t x, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_set_fmpz(fmpz_mpoly_q_numref(res), fmpq_numref(x), ctx); fmpz_mpoly_set_fmpz(fmpz_mpoly_q_denref(res), fmpq_denref(x), ctx); } calcium-0.4.1/fmpz_mpoly_q/set_fmpz.c000066400000000000000000000011551407704557200176550ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_set_fmpz(fmpz_mpoly_q_t res, const fmpz_t x, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_set_fmpz(fmpz_mpoly_q_numref(res), x, ctx); fmpz_mpoly_one(fmpz_mpoly_q_denref(res), ctx); } calcium-0.4.1/fmpz_mpoly_q/set_si.c000066400000000000000000000011421407704557200173100ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_set_si(fmpz_mpoly_q_t res, slong x, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_set_si(fmpz_mpoly_q_numref(res), x, ctx); fmpz_mpoly_one(fmpz_mpoly_q_denref(res), ctx); } calcium-0.4.1/fmpz_mpoly_q/sub.c000066400000000000000000000243571407704557200166300ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" static void _fmpz_mpoly_q_sub_fmpz_mpoly_den(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_mpoly_t y_num, const fmpz_t y_den, const fmpz_mpoly_ctx_t ctx) { fmpz_t g; fmpz_init(g); if (fmpz_mpoly_is_fmpz(y_num, ctx)) { if (res_num == x_num || res_num == y_num) { fmpz_t t, u; fmpz_init_set(t, y_num->coeffs); fmpz_init_set(u, y_den); _fmpz_mpoly_q_sub_fmpq(res_num, res_den, x_num, x_den, t, u, ctx); fmpz_clear(t); fmpz_clear(u); } else { _fmpz_mpoly_q_sub_fmpq(res_num, res_den, x_num, x_den, y_num->coeffs, y_den, ctx); } return; } if (fmpz_mpoly_is_fmpz(x_den, ctx)) { fmpz_gcd(g, x_den->coeffs, y_den); if (fmpz_is_one(g)) { fmpz_mpoly_t t, u; fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); /* todo: avoid one alloc? not helpful right now because fmpz_mpoly_sub does not work inplace */ fmpz_mpoly_scalar_mul_fmpz(t, y_num, x_den->coeffs, ctx); fmpz_mpoly_scalar_mul_fmpz(u, x_num, y_den, ctx); fmpz_mpoly_sub(res_num, u, t, ctx); fmpz_mul(g, x_den->coeffs, y_den); fmpz_mpoly_set_fmpz(res_den, g, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } else { fmpz_t a, b; fmpz_mpoly_t t, u; fmpz_init(a); fmpz_init(b); fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); fmpz_divexact(a, y_den, g); fmpz_divexact(b, x_den->coeffs, g); fmpz_mpoly_scalar_mul_fmpz(t, y_num, b, ctx); fmpz_mpoly_scalar_mul_fmpz(u, x_num, a, ctx); fmpz_mpoly_sub(res_num, u, t, ctx); if (fmpz_mpoly_is_zero(res_num, ctx)) fmpz_one(a); else _fmpz_vec_content2(a, res_num->coeffs, res_num->length, g); if (fmpz_is_one(a)) { fmpz_mul(g, b, y_den); fmpz_mpoly_set_fmpz(res_den, g, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_num, res_num, a, ctx); fmpz_divexact(g, y_den, a); fmpz_mul(g, g, b); fmpz_mpoly_set_fmpz(res_den, g, ctx); } fmpz_clear(a); fmpz_clear(b); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } } else { _fmpz_vec_content2(g, x_den->coeffs, x_den->length, y_den); if (fmpz_is_one(g)) { fmpz_mpoly_t t, u; fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); /* todo: avoid one alloc? not helpful right now because fmpz_mpoly_sub does not work inplace */ fmpz_mpoly_mul(t, y_num, x_den, ctx); fmpz_mpoly_scalar_mul_fmpz(u, x_num, y_den, ctx); fmpz_mpoly_sub(res_num, u, t, ctx); fmpz_set(g, y_den); fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, g, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } else { fmpz_t a; fmpz_mpoly_t b, t, u; fmpz_init(a); fmpz_mpoly_init(b, ctx); fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); fmpz_divexact(a, y_den, g); fmpz_mpoly_scalar_divexact_fmpz(b, x_den, g, ctx); fmpz_mpoly_mul(t, y_num, b, ctx); fmpz_mpoly_scalar_mul_fmpz(u, x_num, a, ctx); fmpz_mpoly_sub(res_num, u, t, ctx); if (fmpz_mpoly_is_zero(res_num, ctx)) fmpz_one(a); else _fmpz_vec_content2(a, res_num->coeffs, res_num->length, g); if (fmpz_is_one(a)) { fmpz_set(g, y_den); fmpz_mpoly_scalar_mul_fmpz(res_den, b, g, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_num, res_num, a, ctx); fmpz_divexact(g, y_den, a); fmpz_mpoly_scalar_mul_fmpz(res_den, b, g, ctx); } fmpz_clear(a); fmpz_mpoly_clear(b, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } } fmpz_clear(g); } void _fmpz_mpoly_q_sub(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_mpoly_t y_num, const fmpz_mpoly_t y_den, const fmpz_mpoly_ctx_t ctx) { if (fmpz_mpoly_is_zero(x_num, ctx)) { fmpz_mpoly_neg(res_num, y_num, ctx); fmpz_mpoly_set(res_den, y_den, ctx); return; } if (fmpz_mpoly_is_zero(y_num, ctx)) { fmpz_mpoly_set(res_num, x_num, ctx); fmpz_mpoly_set(res_den, x_den, ctx); return; } if (fmpz_mpoly_equal(x_den, y_den, ctx)) { fmpz_mpoly_sub(res_num, x_num, y_num, ctx); if (fmpz_mpoly_is_one(x_den, ctx) || fmpz_mpoly_is_zero(res_num, ctx)) { fmpz_mpoly_one(res_den, ctx); } else if (fmpz_mpoly_is_fmpz(x_den, ctx)) { fmpz_t t; fmpz_init(t); _fmpz_vec_content2(t, res_num->coeffs, res_num->length, x_den->coeffs); if (fmpz_is_one(t)) { fmpz_mpoly_set(res_den, x_den, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_num, res_num, t, ctx); fmpz_mpoly_scalar_divexact_fmpz(res_den, x_den, t, ctx); } fmpz_clear(t); } else { fmpz_mpoly_t t; fmpz_mpoly_init(t, ctx); fmpz_mpoly_gcd_assert_successful(t, res_num, x_den, ctx); if (fmpz_mpoly_is_one(t, ctx)) { fmpz_mpoly_set(res_den, x_den, ctx); } else { _fmpz_mpoly_q_mpoly_divexact(res_num, res_num, t, ctx); _fmpz_mpoly_q_mpoly_divexact(res_den, x_den, t, ctx); } fmpz_mpoly_clear(t, ctx); } return; } if (fmpz_mpoly_is_one(x_den, ctx)) { if (res_num == y_num) { fmpz_mpoly_t t; fmpz_mpoly_init(t, ctx); fmpz_mpoly_mul(t, x_num, y_den, ctx); fmpz_mpoly_sub(res_num, t, y_num, ctx); fmpz_mpoly_clear(t, ctx); } else { fmpz_mpoly_mul(res_num, x_num, y_den, ctx); fmpz_mpoly_sub(res_num, res_num, y_num, ctx); } fmpz_mpoly_set(res_den, y_den, ctx); return; } if (fmpz_mpoly_is_one(y_den, ctx)) { if (res_num == x_num) { fmpz_mpoly_t t; fmpz_mpoly_init(t, ctx); fmpz_mpoly_mul(t, y_num, x_den, ctx); fmpz_mpoly_sub(res_num, x_num, t, ctx); fmpz_mpoly_clear(t, ctx); } else { fmpz_mpoly_mul(res_num, y_num, x_den, ctx); fmpz_mpoly_sub(res_num, x_num, res_num, ctx); } fmpz_mpoly_set(res_den, x_den, ctx); return; } if (fmpz_mpoly_is_fmpz(y_den, ctx)) { _fmpz_mpoly_q_sub_fmpz_mpoly_den(res_num, res_den, x_num, x_den, y_num, y_den->coeffs, ctx); return; } if (fmpz_mpoly_is_fmpz(x_den, ctx)) { _fmpz_mpoly_q_sub_fmpz_mpoly_den(res_num, res_den, y_num, y_den, x_num, x_den->coeffs, ctx); fmpz_mpoly_neg(res_num, res_num, ctx); return; } { fmpz_mpoly_t g; fmpz_mpoly_init(g, ctx); fmpz_mpoly_gcd_assert_successful(g, x_den, y_den, ctx); if (fmpz_mpoly_is_one(g, ctx)) { fmpz_mpoly_t t, u; fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); /* todo: avoid one alloc? not helpful right now because fmpz_mpoly_sub does not work inplace */ fmpz_mpoly_mul(t, x_num, y_den, ctx); fmpz_mpoly_mul(u, y_num, x_den, ctx); fmpz_mpoly_sub(res_num, t, u, ctx); fmpz_mpoly_mul(res_den, x_den, y_den, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } else { fmpz_mpoly_t a, b, t, u; fmpz_mpoly_init(a, ctx); fmpz_mpoly_init(b, ctx); fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); _fmpz_mpoly_q_mpoly_divexact(a, x_den, g, ctx); _fmpz_mpoly_q_mpoly_divexact(b, y_den, g, ctx); fmpz_mpoly_mul(t, x_num, b, ctx); fmpz_mpoly_mul(u, y_num, a, ctx); fmpz_mpoly_sub(res_num, t, u, ctx); fmpz_mpoly_gcd_assert_successful(t, res_num, g, ctx); if (fmpz_mpoly_is_one(t, ctx)) { fmpz_mpoly_mul(res_den, x_den, b, ctx); } else { _fmpz_mpoly_q_mpoly_divexact(res_num, res_num, t, ctx); _fmpz_mpoly_q_mpoly_divexact(g, x_den, t, ctx); fmpz_mpoly_mul(res_den, g, b, ctx); } fmpz_mpoly_clear(a, ctx); fmpz_mpoly_clear(b, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } fmpz_mpoly_clear(g, ctx); } } void fmpz_mpoly_q_sub(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) { _fmpz_mpoly_q_sub(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), fmpz_mpoly_q_numref(y), fmpz_mpoly_q_denref(y), ctx); } calcium-0.4.1/fmpz_mpoly_q/sub_fmpq.c000066400000000000000000000110421407704557200176360ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void _fmpz_mpoly_q_sub_fmpq(fmpz_mpoly_t res_num, fmpz_mpoly_t res_den, const fmpz_mpoly_t x_num, const fmpz_mpoly_t x_den, const fmpz_t y_num, const fmpz_t y_den, const fmpz_mpoly_ctx_t ctx) { if (fmpz_is_zero(y_num)) { fmpz_mpoly_set(res_num, x_num, ctx); fmpz_mpoly_set(res_den, x_den, ctx); return; } if (fmpz_mpoly_is_zero(x_num, ctx)) { fmpz_mpoly_set_fmpz(res_num, y_num, ctx); fmpz_neg(res_num->coeffs, res_num->coeffs); fmpz_mpoly_set_fmpz(res_den, y_den, ctx); return; } /* todo: special-case integer x_den */ if (fmpz_mpoly_equal_fmpz(x_den, y_den, ctx)) { fmpz_mpoly_sub_fmpz(res_num, x_num, y_num, ctx); if (fmpz_is_one(y_den)) { fmpz_mpoly_one(res_den, ctx); } else { fmpz_t t; fmpz_init(t); _fmpz_vec_content2(t, res_num->coeffs, res_num->length, y_den); if (fmpz_is_one(t)) { fmpz_mpoly_set(res_den, x_den, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_num, res_num, t, ctx); fmpz_divexact(t, y_den, t); fmpz_mpoly_set_fmpz(res_den, t, ctx); } fmpz_clear(t); } return; } if (fmpz_mpoly_is_one(x_den, ctx)) { fmpz_mpoly_scalar_mul_fmpz(res_num, x_num, y_den, ctx); fmpz_mpoly_sub_fmpz(res_num, res_num, y_num, ctx); fmpz_mpoly_set_fmpz(res_den, y_den, ctx); return; } if (fmpz_is_one(y_den)) { if (res_num == x_num) { fmpz_mpoly_t t; fmpz_mpoly_init(t, ctx); fmpz_mpoly_scalar_mul_fmpz(t, x_den, y_num, ctx); fmpz_mpoly_sub(res_num, x_num, t, ctx); fmpz_mpoly_clear(t, ctx); } else { fmpz_mpoly_scalar_mul_fmpz(res_num, x_den, y_num, ctx); fmpz_mpoly_sub(res_num, x_num, res_num, ctx); } fmpz_mpoly_set(res_den, x_den, ctx); return; } { fmpz_t g; fmpz_init(g); _fmpz_vec_content2(g, x_den->coeffs, x_den->length, y_den); if (fmpz_is_one(g)) { fmpz_mpoly_t t, u; fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); fmpz_mpoly_scalar_mul_fmpz(t, x_num, y_den, ctx); /* todo: avoid one alloc? */ fmpz_mpoly_scalar_mul_fmpz(u, x_den, y_num, ctx); fmpz_mpoly_sub(res_num, t, u, ctx); fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, y_den, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } else { fmpz_mpoly_t t, u; fmpz_t b, c; fmpz_init(b); fmpz_init(c); fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); fmpz_mpoly_scalar_divexact_fmpz(u, x_den, g, ctx); fmpz_divexact(b, y_den, g); fmpz_mpoly_scalar_mul_fmpz(t, x_num, b, ctx); fmpz_mpoly_scalar_mul_fmpz(u, u, y_num, ctx); fmpz_mpoly_sub(res_num, t, u, ctx); _fmpz_vec_content2(c, res_num->coeffs, res_num->length, g); if (fmpz_is_one(c)) { fmpz_mpoly_scalar_mul_fmpz(res_den, x_den, b, ctx); } else { fmpz_mpoly_scalar_divexact_fmpz(res_num, res_num, c, ctx); fmpz_mpoly_scalar_divexact_fmpz(res_den, x_den, c, ctx); fmpz_mpoly_scalar_mul_fmpz(res_den, res_den, b, ctx); } fmpz_clear(b); fmpz_clear(c); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); } fmpz_clear(g); } } void fmpz_mpoly_q_sub_fmpq(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpq_t y, const fmpz_mpoly_ctx_t ctx) { _fmpz_mpoly_q_sub_fmpq(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), fmpq_numref(y), fmpq_denref(y), ctx); } calcium-0.4.1/fmpz_mpoly_q/sub_fmpz.c000066400000000000000000000013621407704557200176530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_sub_fmpz(fmpz_mpoly_q_t res, const fmpz_mpoly_q_t x, const fmpz_t y, const fmpz_mpoly_ctx_t ctx) { fmpz_t one; *one = 1; _fmpz_mpoly_q_sub_fmpq(fmpz_mpoly_q_numref(res), fmpz_mpoly_q_denref(res), fmpz_mpoly_q_numref(x), fmpz_mpoly_q_denref(x), y, one, ctx); } calcium-0.4.1/fmpz_mpoly_q/swap.c000066400000000000000000000012171407704557200167770ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" void fmpz_mpoly_q_swap(fmpz_mpoly_q_t x, fmpz_mpoly_q_t y, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_swap(fmpz_mpoly_q_numref(x), fmpz_mpoly_q_numref(y), ctx); fmpz_mpoly_swap(fmpz_mpoly_q_denref(x), fmpz_mpoly_q_denref(y), ctx); } calcium-0.4.1/fmpz_mpoly_q/test/000077500000000000000000000000001407704557200166375ustar00rootroot00000000000000calcium-0.4.1/fmpz_mpoly_q/test/t-add.c000066400000000000000000000062211407704557200177750ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("add...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 100000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C, D; fmpz_mpoly_t t, u; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpz_mpoly_q_init(D, ctx); fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); fmpz_mpoly_q_randtest(A, state, 5, 2 + n_randint(state, 100), 5, ctx); fmpz_mpoly_q_randtest(B, state, 5, 2 + n_randint(state, 100), 5, ctx); fmpz_mpoly_q_add(C, A, B, ctx); fmpz_mpoly_mul(t, fmpz_mpoly_q_numref(A), fmpz_mpoly_q_denref(B), ctx); fmpz_mpoly_mul(u, fmpz_mpoly_q_numref(B), fmpz_mpoly_q_denref(A), ctx); fmpz_mpoly_add(fmpz_mpoly_q_numref(D), t, u, ctx); fmpz_mpoly_mul(fmpz_mpoly_q_denref(D), fmpz_mpoly_q_denref(A), fmpz_mpoly_q_denref(B), ctx); fmpz_mpoly_q_canonicalise(D, ctx); if (!fmpz_mpoly_q_equal(C, D, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("D = "); fmpz_mpoly_q_print_pretty(D, NULL, ctx); flint_printf("\n\n"); flint_abort(); } if (n_randint(state, 2)) { fmpz_mpoly_q_set(C, A, ctx); fmpz_mpoly_q_add(C, C, B, ctx); } else { fmpz_mpoly_q_set(C, B, ctx); fmpz_mpoly_q_add(C, A, C, ctx); } if (!fmpz_mpoly_q_equal(C, D, ctx)) { flint_printf("FAIL (aliasing)\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("D = "); fmpz_mpoly_q_print_pretty(D, NULL, ctx); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpz_mpoly_q_clear(D, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-add_fmpq.c000066400000000000000000000036011407704557200210170ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("add_fmpq...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C; fmpq_t c; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpq_init(c); fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpq_randtest(c, state, 10); fmpz_mpoly_q_add_fmpq(B, A, c, ctx); fmpz_mpoly_q_set_fmpq(C, c, ctx); fmpz_mpoly_q_add(C, A, C, ctx); if (!fmpz_mpoly_q_equal(B, C, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("c = "); fmpq_print(c); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpq_clear(c); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-add_fmpz.c000066400000000000000000000036011407704557200210300ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("add_fmpz...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C; fmpz_t c; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpz_init(c); fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpz_randtest(c, state, 10); fmpz_mpoly_q_add_fmpz(B, A, c, ctx); fmpz_mpoly_q_set_fmpz(C, c, ctx); fmpz_mpoly_q_add(C, A, C, ctx); if (!fmpz_mpoly_q_equal(B, C, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("c = "); fmpz_print(c); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpz_clear(c); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-div.c000066400000000000000000000056731407704557200200410ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("div...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C, D; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpz_mpoly_q_init(D, ctx); fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); do { fmpz_mpoly_q_randtest(B, state, 10, 2 + n_randint(state, 100), 5, ctx); } while (fmpz_mpoly_q_is_zero(B, ctx)); fmpz_mpoly_q_div(C, A, B, ctx); fmpz_mpoly_mul(fmpz_mpoly_q_numref(D), fmpz_mpoly_q_numref(A), fmpz_mpoly_q_denref(B), ctx); fmpz_mpoly_mul(fmpz_mpoly_q_denref(D), fmpz_mpoly_q_denref(A), fmpz_mpoly_q_numref(B), ctx); fmpz_mpoly_q_canonicalise(D, ctx); if (!fmpz_mpoly_q_equal(C, D, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("D = "); fmpz_mpoly_q_print_pretty(D, NULL, ctx); flint_printf("\n\n"); flint_abort(); } if (n_randint(state, 2)) { fmpz_mpoly_q_set(C, A, ctx); fmpz_mpoly_q_div(C, C, B, ctx); } else { fmpz_mpoly_q_set(C, B, ctx); fmpz_mpoly_q_div(C, A, C, ctx); } if (!fmpz_mpoly_q_equal(C, D, ctx)) { flint_printf("FAIL (aliasing)\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("D = "); fmpz_mpoly_q_print_pretty(D, NULL, ctx); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpz_mpoly_q_clear(D, ctx); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-div_fmpq.c000066400000000000000000000040651407704557200210560ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("div_fmpq...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C; fmpq_t c; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpq_init(c); fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpq_randtest_not_zero(c, state, 10); fmpz_mpoly_q_div_fmpq(B, A, c, ctx); fmpz_mpoly_scalar_mul_fmpz(fmpz_mpoly_q_numref(C), fmpz_mpoly_q_numref(A), fmpq_denref(c), ctx); fmpz_mpoly_scalar_mul_fmpz(fmpz_mpoly_q_denref(C), fmpz_mpoly_q_denref(A), fmpq_numref(c), ctx); fmpz_mpoly_q_canonicalise(C, ctx); if (!fmpz_mpoly_q_equal(B, C, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("c = "); fmpq_print(c); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpq_clear(c); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-div_fmpz.c000066400000000000000000000040141407704557200210610ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("div_fmpz...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C; fmpz_t c; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpz_init(c); fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpz_randtest_not_zero(c, state, 10); fmpz_mpoly_q_div_fmpz(B, A, c, ctx); fmpz_mpoly_set(fmpz_mpoly_q_numref(C), fmpz_mpoly_q_numref(A), ctx); fmpz_mpoly_scalar_mul_fmpz(fmpz_mpoly_q_denref(C), fmpz_mpoly_q_denref(A), c, ctx); fmpz_mpoly_q_canonicalise(C, ctx); if (!fmpz_mpoly_q_equal(B, C, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("c = "); fmpz_print(c); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpz_clear(c); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-inv.c000066400000000000000000000036551407704557200200510ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("inv...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); do { fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); } while (fmpz_mpoly_q_is_zero(A, ctx)); fmpz_mpoly_q_inv(B, A, ctx); if (n_randint(state, 2)) { fmpz_mpoly_q_inv(C, B, ctx); } else { fmpz_mpoly_q_set(C, B, ctx); fmpz_mpoly_q_inv(C, C, ctx); } if (!fmpz_mpoly_q_is_canonical(B, ctx) || !fmpz_mpoly_q_equal(A, C, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-mul.c000066400000000000000000000055721407704557200200520ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("mul...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C, D; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpz_mpoly_q_init(D, ctx); fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpz_mpoly_q_randtest(B, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpz_mpoly_q_mul(C, A, B, ctx); fmpz_mpoly_mul(fmpz_mpoly_q_numref(D), fmpz_mpoly_q_numref(A), fmpz_mpoly_q_numref(B), ctx); fmpz_mpoly_mul(fmpz_mpoly_q_denref(D), fmpz_mpoly_q_denref(A), fmpz_mpoly_q_denref(B), ctx); fmpz_mpoly_q_canonicalise(D, ctx); if (!fmpz_mpoly_q_equal(C, D, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("D = "); fmpz_mpoly_q_print_pretty(D, NULL, ctx); flint_printf("\n\n"); flint_abort(); } if (n_randint(state, 2)) { fmpz_mpoly_q_set(C, A, ctx); fmpz_mpoly_q_mul(C, C, B, ctx); } else { fmpz_mpoly_q_set(C, B, ctx); fmpz_mpoly_q_mul(C, A, C, ctx); } if (!fmpz_mpoly_q_equal(C, D, ctx)) { flint_printf("FAIL (aliasing)\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("D = "); fmpz_mpoly_q_print_pretty(D, NULL, ctx); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpz_mpoly_q_clear(D, ctx); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-mul_fmpq.c000066400000000000000000000040541407704557200210670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("mul_fmpq...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C; fmpq_t c; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpq_init(c); fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpq_randtest(c, state, 10); fmpz_mpoly_q_mul_fmpq(B, A, c, ctx); fmpz_mpoly_scalar_mul_fmpz(fmpz_mpoly_q_numref(C), fmpz_mpoly_q_numref(A), fmpq_numref(c), ctx); fmpz_mpoly_scalar_mul_fmpz(fmpz_mpoly_q_denref(C), fmpz_mpoly_q_denref(A), fmpq_denref(c), ctx); fmpz_mpoly_q_canonicalise(C, ctx); if (!fmpz_mpoly_q_equal(B, C, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("c = "); fmpq_print(c); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpq_clear(c); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-mul_fmpz.c000066400000000000000000000040031407704557200210720ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("mul_fmpz...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C; fmpz_t c; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpz_init(c); fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpz_randtest(c, state, 10); fmpz_mpoly_q_mul_fmpz(B, A, c, ctx); fmpz_mpoly_scalar_mul_fmpz(fmpz_mpoly_q_numref(C), fmpz_mpoly_q_numref(A), c, ctx); fmpz_mpoly_set(fmpz_mpoly_q_denref(C), fmpz_mpoly_q_denref(A), ctx); fmpz_mpoly_q_canonicalise(C, ctx); if (!fmpz_mpoly_q_equal(B, C, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("c = "); fmpz_print(c); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpz_clear(c); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-randtest.c000066400000000000000000000025301407704557200210700ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("randtest...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_randtest(A, state, 10, 10, 5, ctx); /* fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n"); */ if (!fmpz_mpoly_q_is_canonical(A, ctx)) { flint_printf("FAIL: not canonical\n"); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-sub.c000066400000000000000000000062231407704557200200400ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("sub...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 100000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C, D; fmpz_mpoly_t t, u; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpz_mpoly_q_init(D, ctx); fmpz_mpoly_init(t, ctx); fmpz_mpoly_init(u, ctx); fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpz_mpoly_q_randtest(B, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpz_mpoly_q_sub(C, A, B, ctx); fmpz_mpoly_mul(t, fmpz_mpoly_q_numref(A), fmpz_mpoly_q_denref(B), ctx); fmpz_mpoly_mul(u, fmpz_mpoly_q_numref(B), fmpz_mpoly_q_denref(A), ctx); fmpz_mpoly_sub(fmpz_mpoly_q_numref(D), t, u, ctx); fmpz_mpoly_mul(fmpz_mpoly_q_denref(D), fmpz_mpoly_q_denref(A), fmpz_mpoly_q_denref(B), ctx); fmpz_mpoly_q_canonicalise(D, ctx); if (!fmpz_mpoly_q_equal(C, D, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("D = "); fmpz_mpoly_q_print_pretty(D, NULL, ctx); flint_printf("\n\n"); flint_abort(); } if (n_randint(state, 2)) { fmpz_mpoly_q_set(C, A, ctx); fmpz_mpoly_q_sub(C, C, B, ctx); } else { fmpz_mpoly_q_set(C, B, ctx); fmpz_mpoly_q_sub(C, A, C, ctx); } if (!fmpz_mpoly_q_equal(C, D, ctx)) { flint_printf("FAIL (aliasing)\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("D = "); fmpz_mpoly_q_print_pretty(D, NULL, ctx); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpz_mpoly_q_clear(D, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_clear(u, ctx); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-sub_fmpq.c000066400000000000000000000036011407704557200210600ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("sub_fmpq...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C; fmpq_t c; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpq_init(c); fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpq_randtest(c, state, 10); fmpz_mpoly_q_sub_fmpq(B, A, c, ctx); fmpz_mpoly_q_set_fmpq(C, c, ctx); fmpz_mpoly_q_sub(C, A, C, ctx); if (!fmpz_mpoly_q_equal(B, C, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("c = "); fmpq_print(c); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpq_clear(c); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/test/t-sub_fmpz.c000066400000000000000000000036011407704557200210710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" int main() { slong iter; flint_rand_t state; flint_printf("sub_fmpz...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_q_t A, B, C; fmpz_t c; fmpz_mpoly_ctx_init(ctx, 1 + n_randint(state, 4), ORD_LEX); fmpz_mpoly_q_init(A, ctx); fmpz_mpoly_q_init(B, ctx); fmpz_mpoly_q_init(C, ctx); fmpz_init(c); fmpz_mpoly_q_randtest(A, state, 10, 2 + n_randint(state, 100), 5, ctx); fmpz_randtest(c, state, 10); fmpz_mpoly_q_sub_fmpz(B, A, c, ctx); fmpz_mpoly_q_set_fmpz(C, c, ctx); fmpz_mpoly_q_sub(C, A, C, ctx); if (!fmpz_mpoly_q_equal(B, C, ctx)) { flint_printf("FAIL\n"); flint_printf("A = "); fmpz_mpoly_q_print_pretty(A, NULL, ctx); flint_printf("\n\n"); flint_printf("B = "); fmpz_mpoly_q_print_pretty(B, NULL, ctx); flint_printf("\n\n"); flint_printf("C = "); fmpz_mpoly_q_print_pretty(C, NULL, ctx); flint_printf("\n\n"); flint_printf("c = "); fmpz_print(c); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_q_clear(A, ctx); fmpz_mpoly_q_clear(B, ctx); fmpz_mpoly_q_clear(C, ctx); fmpz_clear(c); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/fmpz_mpoly_q/used_vars.c000066400000000000000000000036501407704557200200230ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "fmpz_mpoly_q.h" /* ANDs used without zeroing */ void _fmpz_mpoly_used_vars(int * used, const fmpz_mpoly_t f, const fmpz_mpoly_ctx_t ctx) { slong i, n; fmpz * max; TMP_INIT; n = ctx->minfo->nvars; if (fmpz_mpoly_is_fmpz(f, ctx)) return; /* The polynomial is not constant and has only one variable. */ if (n == 1) { used[0] = 1; return; } TMP_START; max = TMP_ALLOC(sizeof(fmpz) * n); for (i = 0; i < n; i++) fmpz_init(max + i); mpoly_degrees_ffmpz(max, f->exps, f->length, f->bits, ctx->minfo); for (i = 0; i < n; i++) used[i] |= !fmpz_is_zero(max + i); for (i = 0; i < n; i++) fmpz_clear(max + i); TMP_END; } void fmpz_mpoly_q_used_vars(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx) { slong i, n; n = ctx->minfo->nvars; for (i = 0; i < n; i++) used[i] = 0; _fmpz_mpoly_used_vars(used, fmpz_mpoly_q_numref(f), ctx); _fmpz_mpoly_used_vars(used, fmpz_mpoly_q_denref(f), ctx); } void fmpz_mpoly_q_used_vars_num(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx) { slong i, n; n = ctx->minfo->nvars; for (i = 0; i < n; i++) used[i] = 0; _fmpz_mpoly_used_vars(used, fmpz_mpoly_q_numref(f), ctx); } void fmpz_mpoly_q_used_vars_den(int * used, const fmpz_mpoly_q_t f, const fmpz_mpoly_ctx_t ctx) { slong i, n; n = ctx->minfo->nvars; for (i = 0; i < n; i++) used[i] = 0; _fmpz_mpoly_used_vars(used, fmpz_mpoly_q_denref(f), ctx); } calcium-0.4.1/pycalcium/000077500000000000000000000000001407704557200151325ustar00rootroot00000000000000calcium-0.4.1/pycalcium/pyca.py000066400000000000000000004147421407704557200164540ustar00rootroot00000000000000""" Calcium includes a simple Python interface (``pycalcium``, or ``pyca`` for short) implemented using ``ctypes``. Introduction ------------------------------------------------------------------------ Setup and usage .................. Make sure the Calcium library and its dependencies are built and in the path of the system's dynamic library loader. Then make sure that ``/pycalcium`` is in the Python path, for example by adding it to ``PYTHONPATH``, adding it to ``sys.path``, or simply starting Python inside the ``pycalcium`` directory. Import the module and run a calculation: >>> import pyca >>> pyca.ca(1) / 3 0.333333 {1/3} >>> pyca.exp(pyca.pi * pyca.i / 2) 1.00000*I {a where a = I [a^2+1=0]} If you don't mind polluting the global namespace, import everything: >>> from pyca import * >>> exp(pi*i/2) + ca(1)/3 0.333333 + 1.00000*I {(3*a+1)/3 where a = I [a^2+1=0]} Current limitations ..................... * Leaks memory (for example, when printing). * Because ``ctypes`` is used, this is not as efficient as a Cython wrapper. This interface should be used for testing and not for absolute performance. * Does not wrap various functions. API documentation ------------------------------------------------------------------------ Functions are available both as regular functions and as methods on the ``ca`` class. """ import ctypes import ctypes.util import sys libcalcium_path = ctypes.util.find_library('calcium') libcalcium = ctypes.CDLL(libcalcium_path) libarb_path = ctypes.util.find_library('arb') libarb = ctypes.CDLL(libarb_path) libflint_path = ctypes.util.find_library('flint') libflint = ctypes.CDLL(libflint_path) T_TRUE = 0 T_FALSE = 1 T_UNKNOWN = 2 # ctypes.cast(x, ctypes.POINTER(ctypes.c_ulong)) # ctypes.POINTER(ctypes.c_ulong) class _fmpz_struct(ctypes.Structure): _fields_ = [('val', ctypes.c_long)] class _fmpq_struct(ctypes.Structure): _fields_ = [('num', ctypes.c_long), ('den', ctypes.c_long)] def fmpz_to_python_int(xref): ptr = libflint.fmpz_get_str(None, 10, xref) try: return int(ctypes.cast(ptr, ctypes.c_char_p).value.decode()) finally: libflint.flint_free(ptr) # todo def fmpq_set_python(cref, x): assert isinstance(x, int) and -sys.maxsize <= x <= sys.maxsize libflint.fmpq_set_si(cref, x, 1) class _fmpz_poly_struct(ctypes.Structure): _fields_ = [('coeffs', ctypes.c_void_p), ('alloc', ctypes.c_long), ('length', ctypes.c_long)] class _fmpq_poly_struct(ctypes.Structure): _fields_ = [('coeffs', ctypes.c_void_p), ('den', ctypes.c_long), ('alloc', ctypes.c_long), ('length', ctypes.c_long)] class _arb_struct(ctypes.Structure): _fields_ = [('data', ctypes.c_long * 6)] class _acb_struct(ctypes.Structure): _fields_ = [('real', _arb_struct), ('imag', _arb_struct)] class fexpr_struct(ctypes.Structure): """Low-level wrapper for qqbar_struct, for internal use by ctypes.""" _fields_ = [('data', ctypes.c_void_p), ('alloc', ctypes.c_long)] class qqbar_struct(ctypes.Structure): """Low-level wrapper for qqbar_struct, for internal use by ctypes.""" _fields_ = [('poly', _fmpz_poly_struct), ('enclosure', _acb_struct)] class ca_struct(ctypes.Structure): """Low-level wrapper for ca_struct, for internal use by ctypes.""" _fields_ = [('data', ctypes.c_long * 5)] class ca_ctx_struct(ctypes.Structure): """Low-level wrapper for ca_ctx_struct, for internal use by ctypes.""" # todo: use the real size _fields_ = [('content', ctypes.c_ulong * 64)] class ca_mat_struct(ctypes.Structure): """Low-level wrapper for ca_mat_struct, for internal use by ctypes.""" _fields_ = [('entries', ctypes.c_void_p), ('r', ctypes.c_long), ('c', ctypes.c_long), ('rows', ctypes.c_void_p)] class ca_vec_struct(ctypes.Structure): """Low-level wrapper for ca_vec_struct, for internal use by ctypes.""" _fields_ = [('entries', ctypes.c_void_p), ('length', ctypes.c_long), ('alloc', ctypes.c_long)] class ca_poly_struct(ctypes.Structure): """Low-level wrapper for ca_poly_struct, for internal use by ctypes.""" _fields_ = [('coeffs', ctypes.c_void_p), ('length', ctypes.c_long), ('alloc', ctypes.c_long)] class ca_poly_vec_struct(ctypes.Structure): """Low-level wrapper for ca_poly_vec_struct, for internal use by ctypes.""" _fields_ = [('entries', ctypes.POINTER(ca_poly_struct)), ('length', ctypes.c_long), ('alloc', ctypes.c_long)] class fexpr: @staticmethod def inject(vars=False): """ Inject all builtin symbol names into the calling namespace. For interactive use only! >>> fexpr.inject() >>> n = fexpr("n") >>> Sum(Sin(Pi*n/3)/Factorial(n), For(n,0,Infinity)) Sum(Div(Sin(Div(Mul(Pi, n), 3)), Factorial(n)), For(n, 0, Infinity)) """ from inspect import currentframe frame = currentframe().f_back num = libcalcium.fexpr_builtin_length() for i in range(num): # memory leak symbol_name = libcalcium.fexpr_builtin_name(i) symbol_name = symbol_name.decode('ascii') if not symbol_name[0].islower(): frame.f_globals[symbol_name] = fexpr(symbol_name) if vars: def inject_vars(string): for s in string.split(): for symbol_name in [s, s + "_"]: frame.f_globals[symbol_name] = fexpr(symbol_name) inject_vars("""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 z""") inject_vars("""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 Z""") inject_vars("""alpha beta gamma delta epsilon zeta eta theta iota kappa lamda mu nu xi pi rho sigma tau phi chi psi omega ell varphi vartheta""") inject_vars("""Alpha Beta GreekGamma Delta Epsilon Zeta Eta Theta Iota Kappa Lamda Mu Nu Xi GreekPi Rho Sigma Tau Phi Chi Psi Omega""") del frame def builtins(): num = libcalcium.fexpr_builtin_length() names = [] for i in range(num): # memory leak symbol_name = libcalcium.fexpr_builtin_name(i) symbol_name = symbol_name.decode('ascii') names.append(symbol_name) return names def __init__(self, val=None): self._data = fexpr_struct() self._ref = ctypes.byref(self._data) libcalcium.fexpr_init(self) if val is not None: typ = type(val) if typ is int: b = sys.maxsize if -b <= val <= b: libcalcium.fexpr_set_si(self, val) else: n = _fmpz_struct() nref = ctypes.byref(n) libflint.fmpz_init(nref) libflint.fmpz_set_str(nref, ctypes.c_char_p(str(val).encode('ascii')), 10) libcalcium.fexpr_set_fmpz(self, nref) libflint.fmpz_clear(nref) elif typ is str: if val[0] == "'" or val[0] == '"': libcalcium.fexpr_set_string(self, val[1:-1].encode('ascii')) else: libcalcium.fexpr_set_symbol_str(self, val.encode('ascii')) elif typ is float: libcalcium.fexpr_set_d(self, val) elif typ is complex: libcalcium.fexpr_set_re_im_d(self, val.real, val.imag) elif typ is bool: if val: libcalcium.fexpr_set_symbol_str(self, ("True").encode('ascii')) else: libcalcium.fexpr_set_symbol_str(self, ("False").encode('ascii')) elif typ is qqbar: #libcalcium.qqbar_get_fexpr_repr(self, val, val._ctx) tmp = val.fexpr() libcalcium.fexpr_set(self, tmp) elif typ is ca: libcalcium.ca_get_fexpr(self, val, 0, val._ctx) elif typ is ca_mat: libcalcium.ca_mat_get_fexpr(self, val, 0, val._ctx) elif typ is ca_poly: libcalcium.ca_poly_get_fexpr(self, val, 0, val._ctx) elif typ is tuple: tmp = fexpr("Tuple")(*val) # todo: create without copying libcalcium.fexpr_set(self, tmp) elif typ is list: tmp = fexpr("List")(*val) libcalcium.fexpr_set(self, tmp) elif typ is set: tmp = fexpr("Set")(*val) libcalcium.fexpr_set(self, tmp) else: raise TypeError def __del__(self): libcalcium.fexpr_clear(self) @property def _as_parameter_(self): return self._ref @staticmethod def from_param(arg): return arg def __repr__(self): ptr = libcalcium.fexpr_get_str(self) try: return ctypes.cast(ptr, ctypes.c_char_p).value.decode("ascii") finally: libflint.flint_free(ptr) def latex(self): ptr = libcalcium.fexpr_get_str_latex(self, 0) try: return ctypes.cast(ptr, ctypes.c_char_p).value.decode() finally: libflint.flint_free(ptr) def _repr_latex_(self): return "$$" + self.latex() + "$$" def nwords(self): return libcalcium.fexpr_size(self) def size_bytes(self): return libcalcium.fexpr_size_bytes(self) def allocated_bytes(self): return libcalcium.fexpr_allocated_bytes(self) def num_leaves(self): return libcalcium.fexpr_num_leaves(self) def depth(self): return libcalcium.fexpr_depth(self) def __eq__(self, other): if type(self) is not type(other): return NotImplemented if libcalcium.fexpr_equal(self, other): return True return False def is_atom(self): return bool(libcalcium.fexpr_is_atom(self)) def is_atom_integer(self): return bool(libcalcium.fexpr_is_integer(self)) def is_symbol(self): return bool(libcalcium.fexpr_is_symbol(self)) def head(self): if libcalcium.fexpr_is_atom(self): return None res = fexpr() libcalcium.fexpr_func(res, self) return res def nargs(self): # todo: long if self.is_atom(): return None return libcalcium.fexpr_nargs(self) def args(self): if libcalcium.fexpr_is_atom(self): return None n = self.nargs() args = [fexpr() for i in range(n)] for i in range(n): libcalcium.fexpr_arg(args[i], self, i) return tuple(args) def __hash__(self): return libcalcium.fexpr_hash(self) def __call__(self, *args): args2 = [] for arg in args: tp = type(arg) if tp is not fexpr: if tp is str: arg = "'" + arg + "'" arg = fexpr(arg) args2.append(arg) n = len(args2) res = fexpr() if n == 0: libcalcium.fexpr_call0(res, self) elif n == 1: libcalcium.fexpr_call1(res, self, args2[0]) elif n == 2: libcalcium.fexpr_call2(res, self, args2[0], args2[1]) elif n == 3: libcalcium.fexpr_call3(res, self, args2[0], args2[1], args2[2]) elif n == 4: libcalcium.fexpr_call4(res, self, args2[0], args2[1], args2[2], args2[3]) else: vec = libflint.flint_malloc(n * ctypes.sizeof(fexpr_struct)) vec = ctypes.cast(vec, ctypes.POINTER(fexpr_struct)) for i in range(n): vec[i] = args2[i]._data libcalcium.fexpr_call_vec(res, self, vec, n) libflint.flint_free(vec) return res def contains(self, x): """ Check if *x* appears exactly as a subexpression in *self*. >>> f = fexpr("f"); x = fexpr("x"); y = fexpr("y") >>> (f(x+1).contains(f), f(x+1).contains(x), f(x+1).contains(y)) (True, True, False) >>> (f(x+1).contains(1), f(x+1).contains(2)) (True, False) >>> (f(x+1).contains(x+1), f(x+1).contains(f(x+1))) (True, True) """ if type(x) is not fexpr: x = fexpr(x) if libcalcium.fexpr_contains(self, x): return True return False def replace(self, old, new=None): """ Replace subexpression. >>> f = fexpr("f"); x = fexpr("x"); y = fexpr("y") >>> f(x+1, x-1).replace(x, y) f(Add(y, 1), Sub(y, 1)) >>> f(x+1, x-1).replace(x+1, y-1) f(Sub(y, 1), Sub(x, 1)) >>> f(x+1, x-1).replace(f, f+1) Add(f, 1)(Add(x, 1), Sub(x, 1)) >>> f(x+1, x-1).replace(x+2, y) f(Add(x, 1), Sub(x, 1)) """ # todo: dict replacement if type(old) is not fexpr: old = fexpr(old) if type(new) is not fexpr: new = fexpr(new) res = fexpr() libcalcium.fexpr_replace(res, self, old, new) return res def __add__(self, other): if type(self) is not type(other): try: other = fexpr(other) except TypeError: return NotImplemented res = fexpr() libcalcium.fexpr_add(res, self, other) return res def __radd__(self, other): if type(self) is not type(other): try: other = fexpr(other) except TypeError: return NotImplemented res = fexpr() libcalcium.fexpr_add(res, other, self) return res def __sub__(self, other): if type(self) is not type(other): try: other = fexpr(other) except TypeError: return NotImplemented res = fexpr() libcalcium.fexpr_sub(res, self, other) return res def __rsub__(self, other): if type(self) is not type(other): try: other = fexpr(other) except TypeError: return NotImplemented res = fexpr() libcalcium.fexpr_sub(res, other, self) return res def __mul__(self, other): if type(self) is not type(other): try: other = fexpr(other) except TypeError: return NotImplemented res = fexpr() libcalcium.fexpr_mul(res, self, other) return res def __rmul__(self, other): if type(self) is not type(other): try: other = fexpr(other) except TypeError: return NotImplemented res = fexpr() libcalcium.fexpr_mul(res, other, self) return res def __truediv__(self, other): if type(self) is not type(other): try: other = fexpr(other) except TypeError: return NotImplemented res = fexpr() libcalcium.fexpr_div(res, self, other) return res def __rtruediv__(self, other): if type(self) is not type(other): try: other = fexpr(other) except TypeError: return NotImplemented res = fexpr() libcalcium.fexpr_div(res, other, self) return res def __pow__(self, other): if type(self) is not type(other): try: other = fexpr(other) except TypeError: return NotImplemented res = fexpr() libcalcium.fexpr_pow(res, self, other) return res def __rpow__(self, other): if type(self) is not type(other): try: other = fexpr(other) except TypeError: return NotImplemented res = fexpr() libcalcium.fexpr_pow(res, other, self) return res # def __floordiv__(self, other): # return (self / other).floor() # def __rfloordiv__(self, other): # return (other / self).floor() def __bool__(self): return True def __abs__(self): return fexpr("Abs")(self) def __neg__(self): res = fexpr() libcalcium.fexpr_neg(res, self) return res def __pos__(self): return fexpr("Pos")(self) def expanded_normal_form(self): """ Converts this expression to expanded normal form as a formal rational function of its non-arithmetic subexpressions. >>> x = fexpr("x"); y = fexpr("y") >>> (x / x**2).expanded_normal_form() Div(1, x) >>> (((x ** 0) + 3) ** 5).expanded_normal_form() 1024 >>> ((x+y+1)**3 - (y+1)**3 - (x+y)**3 - (x+1)**3).expanded_normal_form() Add(Mul(-1, Pow(x, 3)), Mul(6, x, y), Mul(-1, Pow(y, 3)), -1) >>> (1/((1/y + 1/x))).expanded_normal_form() Div(Mul(x, y), Add(x, y)) >>> (((x+y)**5 * (x-y)) / (x**2 - y**2)).expanded_normal_form() Add(Pow(x, 4), Mul(4, Pow(x, 3), y), Mul(6, Pow(x, 2), Pow(y, 2)), Mul(4, x, Pow(y, 3)), Pow(y, 4)) >>> (1 / (x - x)).expanded_normal_form() Traceback (most recent call last): ... ValueError: expanded_normal_form: overflow, formal division by zero or unsupported expression """ res = fexpr() if not libcalcium.fexpr_expanded_normal_form(res, self, 0): raise ValueError("expanded_normal_form: overflow, formal division by zero or unsupported expression") return res def nstr(self, n=16): """ Evaluates this expression numerically using Arb, returning a decimal string correct within 1 ulp in the last output digit. Attempts to obtain *n* digits (but the actual output accuracy may be lower). >>> Exp = fexpr("Exp"); Exp(1).nstr() '2.718281828459045' >>> Pi = fexpr("Pi"); Pi.nstr(30) '3.14159265358979323846264338328' >>> Log = fexpr("Log"); Log(-2).nstr() '0.6931471805599453 + 3.141592653589793*I' >>> Im = fexpr("Im") >>> Im(Log(2)).nstr() # exact zero '0' Here the imaginary part is zero, but Arb is not able to compute so exactly. The output ``0e-N`` indicates only that the absolute value is bounded by ``1e-N``: >>> Exp(Log(-2)).nstr() '-2.000000000000000 + 0e-22*I' >>> Im(Exp(Log(-2))).nstr() '0e-731' The algorithm fails if the expression or any subexpression is not a finite complex number: >>> Log(0).nstr() Traceback (most recent call last): ... ValueError: nstr: unable to evaluate to a number Expressions must be constant: >>> fexpr("x").nstr() Traceback (most recent call last): ... ValueError: nstr: unable to evaluate to a number """ ptr = libcalcium.fexpr_get_decimal_str(self, n, 0) try: s = ctypes.cast(ptr, ctypes.c_char_p).value.decode("ascii") if s == "?": raise ValueError("nstr: unable to evaluate to a number") return s finally: libflint.flint_free(ptr) class qqbar: """ Wrapper around the qqbar type, representing an algebraic number. >>> (qqbar(2).sqrt() / qqbar(-2).sqrt()) ** 2 -1.00000 (deg 1) >>> qqbar(0.5) == qqbar(1) / 2 True >>> qqbar(0.1) == qqbar(1) / 10 False >>> qqbar(3+4j) 3.00000 + 4.00000*I (deg 2) >>> qqbar(3+4j).root(5) 1.35607 + 0.254419*I (deg 10) >>> qqbar(3+4j).root(5) ** 5 3.00000 + 4.00000*I (deg 2) The constructor can evaluate fexpr symbolic expressions provided that the expressions are constant and composed strictly of algebraic-valued basic operations applied to algebraic numbers. >>> fexpr.inject() >>> qqbar(Pow(0, 0)) 1.00000 (deg 1) >>> qqbar(Sqrt(2) * Abs(1+1j) + (+Re(3-4j)) + (-Im(5+6j))) -1.00000 (deg 1) >>> qqbar((Floor(Sqrt(1000)) + Ceil(Sqrt(1000)) + Sign(1+1j) / Sign(1-1j) + Csgn(1j) + Conjugate(1j)) ** Div(-1, 3)) 0.250000 (deg 1) >>> [qqbar(RootOfUnity(3)), qqbar(RootOfUnity(3,2))] [-0.500000 + 0.866025*I (deg 2), -0.500000 - 0.866025*I (deg 2)] >>> qqbar(Decimal("0.125")) == qqbar(125)/1000 True >>> qqbar(Decimal("-2.7e5")) == -270000 True """ def __init__(self, val=None): self._data = qqbar_struct() self._ref = ctypes.byref(self._data) libcalcium.qqbar_init(self) if val is not None: typ = type(val) if typ is int: b = sys.maxsize if -b <= val <= b: libcalcium.qqbar_set_si(self, val) else: n = _fmpz_struct() nref = ctypes.byref(n) libflint.fmpz_init(nref) libflint.fmpz_set_str(nref, ctypes.c_char_p(str(val).encode('ascii')), 10) libcalcium.qqbar_set_fmpz(self, nref) libflint.fmpz_clear(nref) elif typ is qqbar: libcalcium.qqbar_set(self, val) elif typ is ca: if not libcalcium.ca_get_qqbar(self, val, val._ctx): raise ValueError("unable to parse the given ca as an algebraic number") elif typ is float: libcalcium.qqbar_set_d(self, val) elif typ is complex: libcalcium.qqbar_set_re_im_d(self, val.real, val.imag) elif typ is fexpr: if not libcalcium.qqbar_set_fexpr(self, val): raise ValueError("unable to parse the given fexpr as an algebraic number") else: raise TypeError def __del__(self): libcalcium.qqbar_clear(self) @property def _as_parameter_(self): return self._ref @staticmethod def from_param(arg): return arg def __repr__(self): ptr = libcalcium.qqbar_get_str_nd(self, 6) try: return ctypes.cast(ptr, ctypes.c_char_p).value.decode("ascii") finally: libflint.flint_free(ptr) def _repr_latex_(self): return self.fexpr(formula=False)._repr_latex_() def __bool__(self): """ >>> bool(qqbar(2)) True >>> bool(qqbar(0)) False """ if libcalcium.qqbar_is_zero(self): return False return True def __eq__(self, other): """ >>> qqbar(2)/3 == qqbar(1)/3 False >>> qqbar(2)/3 == 1 - qqbar(1)/3 True >>> qqbar(1) == 1 True >>> qqbar(1) == 2 False """ if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented if libcalcium.qqbar_equal(self, other): return True return False def __ne__(self, other): """ >>> qqbar(2)/3 != qqbar(1)/3 True >>> qqbar(2)/3 != 1 - qqbar(1)/3 False >>> qqbar(1) != 1 False >>> qqbar(1) != 2 True """ if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented if libcalcium.qqbar_equal(self, other): return False return True def __le__(self, other): """ >>> qqbar(2) <= 2 True >>> qqbar(2) <= 1.5 False """ if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented if not (libcalcium.qqbar_is_real(self) and libcalcium.qqbar_is_real(other)): raise ValueError("qqbar order comparison: inputs must be real") c = libcalcium.qqbar_cmp_re(self, other) return c <= 0 def __lt__(self, other): """ >>> qqbar(2) < 3 True >>> qqbar(2) < 2 False >>> qqbar(2) < 1.5 False """ if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented if not (libcalcium.qqbar_is_real(self) and libcalcium.qqbar_is_real(other)): raise ValueError("qqbar order comparison: inputs must be real") c = libcalcium.qqbar_cmp_re(self, other) return c < 0 def __ge__(self, other): """ >>> qqbar(2) >= 2 True >>> qqbar(2) >= 1.5 True >>> qqbar(2) >= 3 False """ if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented if not (libcalcium.qqbar_is_real(self) and libcalcium.qqbar_is_real(other)): raise ValueError("qqbar order comparison: inputs must be real") c = libcalcium.qqbar_cmp_re(self, other) return c >= 0 def __gt__(self, other): """ >>> qqbar(2) > 2 False >>> qqbar(2) > 1.5 True """ if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented if not (libcalcium.qqbar_is_real(self) and libcalcium.qqbar_is_real(other)): raise ValueError("qqbar order comparison: inputs must be real") c = libcalcium.qqbar_cmp_re(self, other) return c > 0 def __add__(self, other): if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented res = qqbar() libcalcium.qqbar_add(res, self, other) return res __radd__ = __add__ def __sub__(self, other): if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented res = qqbar() libcalcium.qqbar_sub(res, self, other) return res def __rsub__(self, other): if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented res = qqbar() libcalcium.qqbar_sub(res, other, self) return res def __mul__(self, other): if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented res = qqbar() libcalcium.qqbar_mul(res, self, other) return res __rmul__ = __mul__ def __truediv__(self, other): if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented if not other: raise ZeroDivisionError res = qqbar() libcalcium.qqbar_div(res, self, other) return res def __rtruediv__(self, other): if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented if not self: raise ZeroDivisionError res = qqbar() libcalcium.qqbar_div(res, other, self) return res def __floordiv__(self, other): return (self / other).floor() def __rfloordiv__(self, other): return (other / self).floor() def __bool__(self): t = libcalcium.qqbar_is_zero(self) if t: return False return True def __abs__(self): res = qqbar() libcalcium.qqbar_abs(res, self) return res def __neg__(self): res = qqbar() libcalcium.qqbar_neg(res, self) return res def __pos__(self): res = qqbar() libcalcium.qqbar_set(res, self) return res def re(self): res = qqbar() libcalcium.qqbar_re(res, self) return res def im(self): res = qqbar() libcalcium.qqbar_im(res, self) return res def conj(self): res = qqbar() libcalcium.qqbar_conj(res, self) return res conjugate = conj def floor(self): res = qqbar() libcalcium.qqbar_floor(res, self) return res def ceil(self): res = qqbar() libcalcium.qqbar_ceil(res, self) return res def sgn(self): """ The sign of this algebraic number. >>> qqbar(-3).sgn() -1.00000 (deg 1) >>> qqbar(2+3j).sgn() 0.554700 + 0.832050*I (deg 4) >>> qqbar(0).sgn() 0 (deg 1) """ res = qqbar() libcalcium.qqbar_sgn(res, self) return res sign = sgn def sqrt(self): """ Principal square root of this algebraic number. >>> qqbar(-1).sqrt() 1.00000*I (deg 2) >>> qqbar(-1).sqrt().sqrt() 0.707107 + 0.707107*I (deg 4) """ res = qqbar() libcalcium.qqbar_sqrt(res, self) return res def root(self, n): """ Principal nth root of this algebraic number. >>> qqbar(3).root(1) 3.00000 (deg 1) >>> qqbar(3).root(2) 1.73205 (deg 2) >>> qqbar(3).root(3) 1.44225 (deg 3) """ assert n >= 1 res = qqbar() libcalcium.qqbar_root_ui(res, self, n) return res @staticmethod def polynomial_roots(coeffs): """ Returns the roots of the polynomial defined by coeffs as a list. Roots are sorted in a fixed, canonical order. At present, the implementation only allows integers (not algebraic numbers) as coefficients. >>> qqbar.polynomial_roots([]) [] >>> qqbar.polynomial_roots([0]) [] >>> qqbar.polynomial_roots([1,2]) [-0.500000 (deg 1)] >>> qqbar.polynomial_roots([3,2,1]) [-1.00000 + 1.41421*I (deg 2), -1.00000 - 1.41421*I (deg 2)] >>> qqbar.polynomial_roots([1,2,1]) [-1.00000 (deg 1), -1.00000 (deg 1)] """ d = len(coeffs) - 1 if d <= 0: return [] c = ctypes.byref(_fmpq_struct()) pol = ctypes.byref(_fmpq_poly_struct()) vec = libcalcium._qqbar_vec_init(d) libflint.fmpq_init(c) libflint.fmpq_poly_init(pol) for i in range(d + 1): fmpq_set_python(c, coeffs[i]) libflint.fmpq_poly_set_coeff_fmpq(pol, i, c) flags = 0 libcalcium.qqbar_roots_fmpq_poly(vec, pol, flags) res = [qqbar() for i in range(d)] for i in range(d): libcalcium.qqbar_set(res[i], ctypes.byref(vec[i])) libcalcium._qqbar_vec_clear(vec, d) libflint.fmpq_clear(c) libflint.fmpq_poly_clear(pol) return res def conjugates(self): """ Returns the algebraic conjugates of this algebraic number. The output is a list, with elements sorted in a fixed, canonical order. >>> qqbar(0).conjugates() [0 (deg 1)] >>> ((qqbar(5).sqrt()+1)/2).conjugates() [1.61803 (deg 2), -0.618034 (deg 2)] >>> qqbar(2+3j).conjugates() [2.00000 + 3.00000*I (deg 2), 2.00000 - 3.00000*I (deg 2)] >>> qqbar.polynomial_roots([4,3,2,1])[0].conjugates() [-1.65063 (deg 3), -0.174685 + 1.54687*I (deg 3), -0.174685 - 1.54687*I (deg 3)] >>> qqbar.polynomial_roots([-35,0,315,0,-693,0,429])[0].conjugates() [0.949108 (deg 6), 0.741531 (deg 6), 0.405845 (deg 6), -0.405845 (deg 6), -0.741531 (deg 6), -0.949108 (deg 6)] """ d = self.degree() if d == 1: return [self] vec = libcalcium._qqbar_vec_init(d) libcalcium.qqbar_conjugates(vec, self) res = [qqbar() for i in range(d)] for i in range(d): libcalcium.qqbar_set(res[i], ctypes.byref(vec[i])) libcalcium._qqbar_vec_clear(vec, d) return res def minpoly(self): """ Returns the minimal polynomial of self over the integers as a list of Python integers specifying the coefficients. >>> qqbar(0).minpoly() [0, 1] >>> (qqbar(2) / 3).minpoly() [-2, 3] >>> qqbar(2).sqrt().minpoly() [-2, 0, 1] >>> ((qqbar(2).sqrt() + 1).root(3) + 1).minpoly() [2, -12, 21, -22, 15, -6, 1] >>> qqbar(0.5).minpoly() [-1, 2] >>> qqbar(0.1).minpoly() [-3602879701896397, 36028797018963968] >>> (qqbar(1) / 10).minpoly() [-1, 10] """ deg = self.degree() c = [0] * (deg + 1) n = _fmpz_struct() nref = ctypes.byref(n) libflint.fmpz_init(nref) poly = ctypes.byref(self._data.poly) for i in range(deg+1): libflint.fmpz_poly_get_coeff_fmpz(nref, poly, i) c[i] = fmpz_to_python_int(nref) libflint.fmpz_clear(nref) return c def is_real(self): """ Check if this algebraic number is a real number. >>> qqbar(2).sqrt().is_real() True >>> qqbar(-2).sqrt().is_real() False """ if libcalcium.qqbar_is_real(self): return True return False def is_rational(self): """ Check if this algebraic number is a rational number. >>> (qqbar(-5) / 7).is_rational() True >>> (qqbar(-5) / 7).sqrt().is_rational() False """ if libcalcium.qqbar_is_rational(self): return True return False def is_integer(self): """ Check if this algebraic number is an integer. >>> qqbar(3).is_integer() True >>> (qqbar(3) / 5).is_integer() False """ if libcalcium.qqbar_is_integer(self): return True return False def degree(self): """ The degree of this algebraic number (the degree of the minimal polynomial). >>> qqbar(5).degree() 1 >>> qqbar(5).sqrt().degree() 2 """ return int(libcalcium.qqbar_degree(self)) def p(self): """ Assuming that self is a rational number, returns the numerator as a Python integer. >>> (qqbar(-2)/3).p() -2 >>> qqbar(-1).sqrt().p() Traceback (most recent call last): ... ValueError: self must be a rational number """ if not self.is_rational(): raise ValueError("self must be a rational number") n = _fmpz_struct() nref = ctypes.byref(n) libflint.fmpz_init(nref) poly = ctypes.byref(self._data.poly) libflint.fmpz_poly_get_coeff_fmpz(nref, poly, 0) libflint.fmpz_neg(nref, nref) res = fmpz_to_python_int(nref) libflint.fmpz_clear(nref) return res def q(self): """ Assuming that self is a rational number, returns the denominator as a Python integer. >>> (qqbar(-2)/3).q() 3 >>> qqbar(-1).sqrt().q() Traceback (most recent call last): ... ValueError: self must be a rational number """ if not self.is_rational(): raise ValueError("self must be a rational number") n = _fmpz_struct() nref = ctypes.byref(n) libflint.fmpz_init(nref) poly = ctypes.byref(self._data.poly) libflint.fmpz_poly_get_coeff_fmpz(nref, poly, 1) res = fmpz_to_python_int(nref) libflint.fmpz_clear(nref) return res def __pow__(self, other): """ >>> qqbar(2) ** (qqbar(1) / 2) 1.41421 (deg 2) >>> (1 / qqbar(64)) ** (qqbar(1) / 3) 0.250000 (deg 1) >>> (-1 / qqbar(64)) ** (qqbar(1) / 3) 0.125000 + 0.216506*I (deg 2) >>> qqbar(1+1j) ** 123 -2.30584e+18 + 2.30584e+18*I (deg 2) >>> qqbar(1+1j) ** 124 -4.61169e+18 (deg 1) >>> qqbar(2+3j) ** (qqbar(1) / 4) 1.33660 + 0.335171*I (deg 8) >>> qqbar(2+3j) ** qqbar(1+2j) Traceback (most recent call last): ... ValueError: qqbar powering: transcendental result >>> qqbar(0) ** 0 1.00000 (deg 1) >>> qqbar(0) ** -1 Traceback (most recent call last): ... ZeroDivisionError >>> qqbar(1) ** qqbar(2).sqrt() 1.00000 (deg 1) >>> qqbar(0) ** qqbar(2).sqrt() 0 (deg 1) >>> qqbar(0) ** (-qqbar(2).sqrt()) Traceback (most recent call last): ... ZeroDivisionError A special code path is implemented for roots of unity: >>> qqbar(-1).root(23) ** (qqbar(10**100) / qqbar(7)) 0.981022 - 0.193894*I (deg 132) """ if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented res = qqbar() if libcalcium.qqbar_pow(res, self, other): return res else: if not self: raise ZeroDivisionError raise ValueError("qqbar powering: transcendental result") def __rpow__(self, other): if type(self) is not type(other): try: other = qqbar(other) except TypeError: return NotImplemented return other ** self def fexpr(self, formula=True, root_index=False, serialized=False, gaussians=True, quadratics=True, cyclotomics=True, cubics=True, quartics=True, quintics=True, depression=True, deflation=True, separation=True): """ """ res = fexpr() if formula: flags = 0 if gaussians: flags |= 1 if quadratics: flags |= 2 if cyclotomics: flags |= 4 if cubics: flags |= 8 if quartics: flags |= 16 if quintics: flags |= 32 if depression: flags |= 64 if deflation: flags |= 128 if separation: flags |= 256 if libcalcium.qqbar_get_fexpr_formula(res, self, flags): return res if root_index: libcalcium.qqbar_get_fexpr_root_indexed(res, self) return res if serialized: libcalcium.qqbar_get_fexpr_repr(res, self) return res libcalcium.qqbar_get_fexpr_root_nearest(res, self) return res def fexpr_repr(self): """ """ res = fexpr() libcalcium.qqbar_get_fexpr_repr(res, self) return res _ca_options = [ "verbose", "print_flags", "mpoly_ord", "prec_limit", "qqbar_deg_limit", "low_prec", "smooth_limit", "lll_prec", "pow_limit", "use_gb", "gb_length_limit", "gb_poly_length_limit", "gb_poly_bits_limit", "vieta_limit", "trig_form"] class ca_ctx: """ Python class wrapping the ca_ctx_t context object. Currently only supports a global instance. """ def __init__(self, **kwargs): self._data = ca_ctx_struct() self._ref = ctypes.byref(self._data) libcalcium.ca_ctx_init(self._ref) for w in kwargs: i = _ca_options.index(w) if i == -1: raise ValueError("unknown option %s" % w) libcalcium.ca_ctx_set_option(self._ref, i, kwargs[w]) def __del__(self): # Python calls ctx_default.__del__ before all ca instances are # destroyed, despite the fact that the ca instances contain # references to ctx_default. # WHY?????????????? # libcalcium.ca_ctx_clear(self._ref) pass def _no_gb(self): libcalcium.ca_ctx_set_option(self, _ca_options.index("use_gb"), 0) def _no_gb_limits(self): libcalcium.ca_ctx_set_option(self, _ca_options.index("gb_length_limit"), 1<<30) libcalcium.ca_ctx_set_option(self, _ca_options.index("gb_poly_length_limit"), 1<<30) libcalcium.ca_ctx_set_option(self, _ca_options.index("gb_poly_bits_limit"), 1<<30) def _debug(self): libcalcium.ca_ctx_set_option(self, _ca_options.index("verbose"), 1) libcalcium.ca_ctx_set_option(self, _ca_options.index("print_flags"), (1 | 2 | 4)) def __repr__(self): s = "ca_ctx(" for i in range(len(_ca_options)): val = libcalcium.ca_ctx_get_option(self._ref, i) s += "%s=%s" % (_ca_options[i], val) if i < len(_ca_options) - 1: s += ", " s += ")" return s @property def _as_parameter_(self): return self._ref @staticmethod def from_param(arg): return arg ctx_default = ca_ctx() class ca: """ Python class wrapping the ca_t type for numbers. Examples:: >>> ca(1) 1 >>> ca() 0 >>> ca(0) 0 >>> ca(-5) -5 >>> ca(2.25) 2.25000 {9/4} >>> ca(1) / 3 0.333333 {1/3} >>> (-1) ** ca(0.5) 1.00000*I {a where a = I [a^2+1=0]} >>> ca(1-2j) 1.00000 - 2.00000*I {-2*a+1 where a = I [a^2+1=0]} >>> ca(0.1) # be careful with float input! 0.100000 {3602879701896397/36028797018963968} >>> ca(float("inf")) +Infinity >>> ca(float("nan")) Unknown >>> 3 < pi < ca(22)/7 True >>> ca(qqbar(200).sqrt()) 14.1421 {10*a where a = 1.41421 [a^2-2=0]} """ def __init__(self, val=None, context=None): if context is None: self._ctx_python = ctx_default else: self._ctx_python = context self._ctx = self._ctx_python._ref self._data = ca_struct() self._ref = ctypes.byref(self._data) libcalcium.ca_init(self, self._ctx) if val is not None: typ = type(val) if typ is int: b = sys.maxsize if -b <= val <= b: libcalcium.ca_set_si(self, val, self._ctx) else: n = _fmpz_struct() nref = ctypes.byref(n) libflint.fmpz_init(nref) libflint.fmpz_set_str(nref, ctypes.c_char_p(str(val).encode('ascii')), 10) libcalcium.ca_set_fmpz(self, nref, self._ctx) libflint.fmpz_clear(nref) elif typ is ca: libcalcium.ca_transfer(self, self._ctx, val, val._ctx) elif typ is float: libcalcium.ca_set_d(self, val, self._ctx) elif typ is complex: libcalcium.ca_set_d_d(self, val.real, val.imag, self._ctx) elif typ is qqbar: libcalcium.ca_set_qqbar(self, val, self._ctx) elif typ is fexpr: if not libcalcium.ca_set_fexpr(self, val, self._ctx): raise ValueError("unable to parse the given expression as a ca") else: raise TypeError def __del__(self): libcalcium.ca_clear(self, self._ctx) @property def _as_parameter_(self): return self._ref @staticmethod def from_param(arg): return arg @staticmethod def inf(): """ The special value positive infinity. Examples:: >>> inf == ca.inf() # alias for the method True >>> inf +Infinity >>> -inf -Infinity >>> abs(-inf) +Infinity >>> inf + inf +Infinity >>> (-inf) + (-inf) -Infinity >>> -inf * inf -Infinity >>> inf / inf Undefined >>> 1 / inf 0 >>> re(inf) Undefined >>> im(inf) Undefined >>> sign(inf) 1 >>> sign((1+i)*inf) == (1+i)/sqrt(2) True """ res = ca() libcalcium.ca_pos_inf(res, res._ctx) return res @staticmethod def uinf(): """ The special value unsigned infinity. Examples:: >>> uinf == ca.uinf() # alias for the method True >>> uinf UnsignedInfinity >>> abs(uinf) +Infinity >>> -3 * uinf UnsignedInfinity >>> 1/uinf 0 >>> sign(uinf) Undefined >>> uinf * uinf UnsignedInfinity >>> uinf / uinf Undefined >>> uinf + uinf Undefined >>> re(uinf) Undefined >>> im(uinf) Undefined """ res = ca() libcalcium.ca_uinf(res, res._ctx) return res @staticmethod def undefined(): """ The special value undefined. Examples:: >>> undefined == ca.undefined() # alias for the method True >>> undefined Undefined >>> undefined == undefined True >>> undefined * 0 Undefined """ res = ca() libcalcium.ca_undefined(res, res._ctx) return res @staticmethod def unknown(): """ The special meta-value unknown. This meta-value is not comparable. Examples:: >>> unknown == unknown Traceback (most recent call last): ... NotImplementedError: unable to decide predicate: equal >>> unknown == 0 Traceback (most recent call last): ... NotImplementedError: unable to decide predicate: equal >>> unknown == undefined Traceback (most recent call last): ... NotImplementedError: unable to decide predicate: equal >>> unknown + unknown Unknown >>> unknown + 3 Unknown >>> unknown + undefined Undefined """ res = ca() libcalcium.ca_unknown(res, res._ctx) return res @staticmethod def pi(): """ The constant pi. Examples:: >>> pi == ca.pi() # alias for the method True >>> pi 3.14159 {a where a = 3.14159 [Pi]} >>> sin(pi/6) 0.500000 {1/2} >>> (pi - 3) ** 3 0.00283872 {a^3-9*a^2+27*a-27 where a = 3.14159 [Pi]} """ res = ca() libcalcium.ca_pi(res, res._ctx) return res @staticmethod def euler(): """ Euler's constant (gamma). Examples:: >>> euler == ca.euler() # alias for the method True >>> euler 0.577216 {a where a = 0.577216 [Euler]} >>> exp(euler) 1.78107 {a where a = 1.78107 [Exp(0.577216 {b})], b = 0.577216 [Euler]} """ res = ca() libcalcium.ca_euler(res, res._ctx) return res @staticmethod def i(): """ The imaginary unit. Examples:: >>> i == ca.i() # alias for the method True >>> i == I == j # extra aliases for convenience True >>> i 1.00000*I {a where a = I [a^2+1=0]} >>> i**2 -1 >>> i**3 -1.00000*I {-a where a = I [a^2+1=0]} >>> abs(i) 1 >>> sign(i) 1.00000*I {a where a = I [a^2+1=0]} >>> abs(sqrt(1+i) / sqrt(1-i)) 1 >>> re(i), im(i) (0, 1) """ res = ca() libcalcium.ca_i(res, res._ctx) return res def __repr__(self): ptr = libcalcium.ca_get_str(self, self._ctx) try: return ctypes.cast(ptr, ctypes.c_char_p).value.decode('ascii') finally: libflint.flint_free(ptr) def __str__(self): return self.__repr__() def _repr_latex_(self): return fexpr(self)._repr_latex_() def __bool__(self): t = libcalcium.ca_check_is_zero(self, self._ctx) if t == T_TRUE: return False if t == T_FALSE: return True raise NotImplementedError("unable to decide predicate: is_zero") @staticmethod def operands_with_same_context(a, b): type_a = type(a) type_b = type(b) if type_a is ca and type_b is ca: if a._ctx_python is b._ctx_python: return a, b # which context object to choose? c = a._new() libcalcium.ca_transfer(c, c._ctx, b, b._ctx) return a, c if type_a is ca: try: b = ca(b, context=a._ctx_python) except TypeError: return NotImplemented, NotImplemented return a, b else: try: a = ca(a, context=b._ctx_python) except TypeError: return NotImplemented, NotImplemented return a, b return NotImplemented, NotImplemented def __eq__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self t = libcalcium.ca_check_equal(self, other, self._ctx) if t == T_TRUE: return True if t == T_FALSE: return False raise NotImplementedError("unable to decide predicate: equal") def __ne__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self t = libcalcium.ca_check_equal(self, other, self._ctx) if t == T_TRUE: return False if t == T_FALSE: return True raise NotImplementedError("unable to decide predicate: equal") def __le__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self t = libcalcium.ca_check_le(self, other, self._ctx) if t == T_TRUE: return True if t == T_FALSE: return False raise NotImplementedError("unable to decide predicate: le") def __lt__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self t = libcalcium.ca_check_lt(self, other, self._ctx) if t == T_TRUE: return True if t == T_FALSE: return False raise NotImplementedError("unable to decide predicate: lt") def __ge__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self t = libcalcium.ca_check_ge(self, other, self._ctx) if t == T_TRUE: return True if t == T_FALSE: return False raise NotImplementedError("unable to decide predicate: ge") def __gt__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self t = libcalcium.ca_check_gt(self, other, self._ctx) if t == T_TRUE: return True if t == T_FALSE: return False raise NotImplementedError("unable to decide predicate: gt") def _new(self): return ca(context=self._ctx_python) def __add__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_add(res, self, other, self._ctx) return res __radd__ = __add__ def __sub__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_sub(res, self, other, self._ctx) return res def __rsub__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_sub(res, other, self, self._ctx) return res def __mul__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_mul(res, self, other, self._ctx) return res __rmul__ = __mul__ def __truediv__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_div(res, self, other, self._ctx) return res def __rtruediv__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_div(res, other, self, self._ctx) return res def __floordiv__(self, other): return (self / other).floor() def __rfloordiv__(self, other): return (other / self).floor() def __pow__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_pow(res, self, other, self._ctx) return res def __rpow__(self, other): self, other = ca.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_pow(res, other, self, self._ctx) return res def pow_arithmetic(self, n): res = self._new() n = int(n) libcalcium.ca_pow_si_arithmetic(res, self, n, self._ctx) return res def __abs__(self): res = self._new() libcalcium.ca_abs(res, self, self._ctx) return res def __neg__(self): res = self._new() libcalcium.ca_neg(res, self, self._ctx) return res def __pos__(self): res = self._new() libcalcium.ca_set(res, self, self._ctx) return res def nstr(self, n=16, parts=False): """ Evaluates this expression numerically using Arb, returning a decimal string correct within 1 ulp in the last output digit. Attempts to obtain *n* digits (but the actual output accuracy may be lower). Examples:: >>> ca(0).nstr() '0' >>> pi.nstr(30) '3.14159265358979323846264338328' By default, the result is considered accurate when the larger of the real and imaginary parts is known to *n* digits. If *parts* is set, the algorithm will attempt to compute both real and imaginary parts accurately. It will, in particular, attempt to recognize when a real or imaginary part is exactly zero:: >>> (log(1+i) + log(1-i)).nstr() '0.6931471805599453 + 0e-25*I' >>> (log(1+i) + log(1-i)).nstr(parts=True) '0.6931471805599453' An exception is raised if the numerical evaluation code fails to produce a finite enclosure:: >>> (1 / ca(0)).nstr() Traceback (most recent call last): ... ValueError: nstr: unable to evaluate to a number """ ptr = libcalcium.ca_get_decimal_str(self, n, parts, self._ctx) try: s = ctypes.cast(ptr, ctypes.c_char_p).value.decode("ascii") if s == "?": raise ValueError("nstr: unable to evaluate to a number") return s finally: libflint.flint_free(ptr) def rewrite_cnf(self, deep=True): res = self._new() libcalcium.ca_rewrite_complex_normal_form(res, self, deep, self._ctx) return res def re(self): """ Real part. Examples:: >>> re(2+3j) == ca(2+3j).re() True >>> re(2+3*i) 2 """ res = self._new() libcalcium.ca_re(res, self, self._ctx) return res def im(self): """ Imaginary part. Examples:: >>> im(2+3j) == ca(2+3j).im() # alias for the method True >>> im(2+3*i) 3 """ res = self._new() libcalcium.ca_im(res, self, self._ctx) return res def conj(self): """ Complex conjugate. Examples:: >>> conj(1j) == conjugate(1j) == ca(1j).conj() == ca(1j).conjugate() # alias for the method True >>> conj(2+i) 2.00000 - 1.00000*I {-a+2 where a = I [a^2+1=0]} >>> conj(pi) 3.14159 {a where a = 3.14159 [Pi]} """ res = self._new() libcalcium.ca_conj(res, self, self._ctx) return res conjugate = conj def floor(self): """ Floor function. Examples:: >>> floor(3) == ca(3).floor() # alias for the method True >>> floor(pi) 3 >>> floor(-pi) -4 """ res = self._new() libcalcium.ca_floor(res, self, self._ctx) return res def ceil(self): """ Ceiling function. Examples:: >>> ceil(3) == ca(3).ceil() # alias for the method True >>> ceil(pi) 4 >>> ceil(-pi) -3 """ res = self._new() libcalcium.ca_ceil(res, self, self._ctx) return res def sgn(self): """ Sign function. Examples:: >>> sgn(2) == sign(2) == ca(2).sgn() # aliases for the method True >>> sign(0) 0 >>> sign(sqrt(2)) 1 >>> sign(-sqrt(2)) -1 >>> sign(-sqrt(-2)) -1.00000*I {-a where a = I [a^2+1=0]} """ res = self._new() libcalcium.ca_sgn(res, self, self._ctx) return res sign = sgn def csgn(self): """ Real-valued complex extension of real sign function. Examples:: >>> csgn(3) 1 >>> csgn(3*i) 1 >>> csgn(-3*i) -1 >>> csgn(-3) -1 >>> csgn(0) 0 >>> csgn(1+i) 1 >>> csgn((1+i)*inf) 1 >>> csgn(-i*inf) -1 >>> csgn(uinf) Undefined """ res = self._new() libcalcium.ca_csgn(res, self, self._ctx) return res def arg(self): """ Complex argument (phase). Examples:: >>> arg(2) == arg(0) == ca(0).arg() == 0 True >>> arg(-10) -3.14159 {-a where a = 3.14159 [Pi]} >>> arg(sqrt(-3)) 1.57080 {(a)/2 where a = 3.14159 [Pi]} >>> arg(-sqrt(sqrt(-3))) -2.35619 {(-3*a)/4 where a = 3.14159 [Pi]} """ res = self._new() libcalcium.ca_arg(res, self, self._ctx) return res def sqrt(self): """ Principal square root. Examples:: >>> sqrt(2) == ca(2).sqrt() # alias for the method True >>> sqrt(0) 0 >>> sqrt(1) 1 >>> sqrt(2) 1.41421 {a where a = 1.41421 [a^2-2=0]} >>> sqrt(-1) 1.00000*I {a where a = I [a^2+1=0]} >>> sqrt(inf) +Infinity >>> sqrt(-inf) +I * Infinity >>> sqrt(uinf) UnsignedInfinity >>> sqrt(undefined) Undefined >>> sqrt(unknown) Unknown """ res = self._new() libcalcium.ca_sqrt(res, self, self._ctx) return res def log(self): """ Natural logarithm. Examples:: >>> log(2) == ca(2).log() # alias for the method True >>> log(1) 0 >>> log(exp(2)) 2 >>> log(2) 0.693147 {a where a = 0.693147 [Log(2)]} >>> log(4) == 2*log(2) True >>> log(1+sqrt(2)) / log(3+2*sqrt(2)) 0.500000 {1/2} >>> log(ca(10)**(10**30)) / log(10) 1.00000e+30 {1000000000000000000000000000000} >>> log(-1) 3.14159*I {a*b where a = 3.14159 [Pi], b = I [b^2+1=0]} >>> log(i) 1.57080*I {(a*b)/2 where a = 3.14159 [Pi], b = I [b^2+1=0]} >>> log(0) -Infinity >>> log(inf) +Infinity >>> log(-inf) +Infinity >>> log(uinf) +Infinity >>> log(undefined) Undefined >>> log(unknown) Unknown """ res = self._new() libcalcium.ca_log(res, self, self._ctx) return res def exp(self): """ Exponential function. Examples:: >>> exp(0) 1 >>> exp(1) 2.71828 {a where a = 2.71828 [Exp(1)]} >>> exp(-1) 0.367879 {a where a = 0.367879 [Exp(-1)]} >>> exp(-1) * exp(1) 1 >>> exp(7*pi*i/2) -1.00000*I {-a where a = I [a^2+1=0]} >>> exp(inf) +Infinity >>> exp(-inf) 0 >>> exp(uinf) Undefined >>> exp(undefined) Undefined >>> exp(unknown) Unknown """ res = self._new() libcalcium.ca_exp(res, self, self._ctx) return res def sin(self, form=None): """ Sine function. Examples:: >>> sin(0) 0 >>> sin(pi) 0 >>> sin(pi/2) 1 >>> sin(pi/6) 0.500000 {1/2} >>> sin(sqrt(2))**2 + cos(sqrt(2))**2 1 >>> sin(3 + pi) + sin(3) 0 >>> sin(1, form="exponential") 0.841471 - 0e-24*I {(-a^2*b+b)/(2*a) where a = 0.540302 + 0.841471*I [Exp(1.00000*I {b})], b = I [b^2+1=0]} >>> sin(1, form="direct") 0.841471 {a where a = 0.841471 [Sin(1)]} >>> sin(1, form="tangent") 0.841471 {(2*a)/(a^2+1) where a = 0.546302 [Tan(0.500000 {1/2})]} >>> sin(inf) Undefined >>> sin(i * inf) +I * Infinity >>> sin(-i * inf) -I * Infinity """ res = self._new() if form is None: libcalcium.ca_sin_cos(res, None, self, self._ctx) elif form == "exponential": libcalcium.ca_sin_cos_exponential(res, None, self, self._ctx) elif form == "tangent": libcalcium.ca_sin_cos_tangent(res, None, self, self._ctx) elif form == "direct": libcalcium.ca_sin_cos_direct(res, None, self, self._ctx) else: raise ValueError("unknown form") return res def cos(self, form=None): """ Cosine function. Examples:: >>> cos(0) 1 >>> cos(pi) -1 >>> cos(pi/2) 0 >>> cos(pi/3) 0.500000 {1/2} >>> cos(pi/6)**2 0.750000 {3/4} >>> cos(1)**2 + sin(1)**2 1 >>> cos(1, form="exponential") 0.540302 - 0e-24*I {(a^2+1)/(2*a) where a = 0.540302 + 0.841471*I [Exp(1.00000*I {b})], b = I [b^2+1=0]} >>> cos(1, form="direct") 0.540302 {a where a = 0.540302 [Cos(1)]} >>> cos(1, form="tangent") 0.540302 {(-a^2+1)/(a^2+1) where a = 0.546302 [Tan(0.500000 {1/2})]} >>> cos(i * inf) +Infinity >>> cos(-i * inf) +Infinity >>> cos(inf) Undefined """ res = self._new() if form is None: libcalcium.ca_sin_cos(None, res, self, self._ctx) elif form == "exponential": libcalcium.ca_sin_cos_exponential(None, res, self, self._ctx) elif form == "tangent": libcalcium.ca_sin_cos_tangent(None, res, self, self._ctx) elif form == "direct": libcalcium.ca_sin_cos_direct(None, res, self, self._ctx) else: raise ValueError("unknown form") return res def tan(self, form=None): """ Tangent function. Examples:: >>> tan(0) 0 >>> tan(pi) 0 >>> tan(pi/2) UnsignedInfinity >>> tan(pi/4) 1 >>> tan(3*pi/4) -1 >>> tan(pi/3)**2 3 >>> tan(1 + pi) - tan(1) 0 >>> tan(1, form="direct") 1.55741 {a where a = 1.55741 [Tan(1)]} >>> tan(1, form="sine_cosine") 1.55741 {(b)/(a) where a = 0.540302 [Cos(1)], b = 0.841471 [Sin(1)]} >>> tan(1, form="exponential") 1.55741 + 0e-23*I {(-a^2*b+b)/(a^2+1) where a = 0.540302 + 0.841471*I [Exp(1.00000*I {b})], b = I [b^2+1=0]} >>> tan(inf) Undefined >>> tan(i * inf) 1.00000*I {a where a = I [a^2+1=0]} >>> tan(-i * inf) -1.00000*I {-a where a = I [a^2+1=0]} """ res = self._new() if form is None: libcalcium.ca_tan(res, self, self._ctx) elif form == "exponential": libcalcium.ca_tan_exponential(res, self, self._ctx) elif form == "direct": libcalcium.ca_tan_direct(res, self, self._ctx) elif form == "sine_cosine": libcalcium.ca_tan_sine_cosine(res, self, self._ctx) else: raise ValueError("unknown form") return res def atan(self, form=None): """ Inverse tangent function. Examples:: >>> atan(0) 0 >>> atan(1) 0.785398 {(a)/4 where a = 3.14159 [Pi]} >>> atan(1-sqrt(2)) -0.392699 {(-a)/8 where a = 3.14159 [Pi]} >>> atan(inf) 1.57080 {(a)/2 where a = 3.14159 [Pi]} >>> atan(-inf) -1.57080 {(-a)/2 where a = 3.14159 [Pi]} >>> atan(i*inf) 1.57080 {(a)/2 where a = 3.14159 [Pi]} >>> atan(-i*inf) -1.57080 {(-a)/2 where a = 3.14159 [Pi]} >>> atan((1+i)*inf) 1.57080 {(a)/2 where a = 3.14159 [Pi]} >>> atan(tan(23*pi/27)) == -4*pi/27 True >>> atan(2, form="direct") 1.10715 {a where a = 1.10715 [Atan(2)]} >>> atan(2, form="logarithm") 1.10715 - 0e-24*I {(a*b)/2 where a = 0e-24 - 2.21430*I [Log(-0.600000 - 0.800000*I {(-4*b-3)/5})], b = I [b^2+1=0]} """ res = self._new() if form is None: libcalcium.ca_atan(res, self, self._ctx) elif form == "exponential" or form == "logarithm": libcalcium.ca_atan_logarithm(res, self, self._ctx) else: libcalcium.ca_atan_direct(res, self, self._ctx) return res def asin(self, form=None): """ Inverse sine function. Examples:: >>> asin(0) 0 >>> asin(1) 1.57080 {(a)/2 where a = 3.14159 [Pi]} >>> asin(-1) -1.57080 {(-a)/2 where a = 3.14159 [Pi]} >>> asin(sqrt(2)/2) 0.785398 {(a)/4 where a = 3.14159 [Pi]} >>> asin(i) 0.881374*I {-a*c where a = -0.881374 [Log(0.414214 {b-1})], b = 1.41421 [b^2-2=0], c = I [c^2+1=0]} >>> sin(asin(sqrt(2)-1)) == sqrt(2)-1 True >>> asin(sin(sqrt(2)-1)) == sqrt(2)-1 True >>> asin(sqrt(2)-1, form="logarithm") 0.427079 + 0e-24*I {-a*d where a = 0e-24 + 0.427079*I [Log(0.910180 + 0.414214*I {b+c*d-d})], b = 0.910180 [Sqrt(0.828427 {2*c-2})], c = 1.41421 [c^2-2=0], d = I [d^2+1=0]} >>> asin(sqrt(2)-1, form="direct") 0.427079 {a where a = 0.427079 [Asin(0.414214 {b-1})], b = 1.41421 [b^2-2=0]} >>> asin(inf) -I * Infinity >>> asin(-inf) +I * Infinity >>> asin(inf*i) +I * Infinity >>> asin(-inf*i) -I * Infinity >>> asin(uinf) UnsignedInfinity >>> asin(undefined) Undefined """ res = self._new() if form is None: libcalcium.ca_asin(res, self, self._ctx) elif form == "exponential" or form == "logarithm": libcalcium.ca_asin_logarithm(res, self, self._ctx) else: libcalcium.ca_asin_direct(res, self, self._ctx) return res def acos(self, form=None): """ Inverse cosine function. Examples:: >>> acos(0) 1.57080 {(a)/2 where a = 3.14159 [Pi]} >>> acos(1) 0 >>> acos(-1) 3.14159 {a where a = 3.14159 [Pi]} >>> acos(sqrt(2)/2) 0.785398 {(a)/4 where a = 3.14159 [Pi]} >>> acos(i) 1.57080 - 0.881374*I {(2*a*d+b)/2 where a = -0.881374 [Log(0.414214 {c-1})], b = 3.14159 [Pi], c = 1.41421 [c^2-2=0], d = I [d^2+1=0]} >>> cos(acos(sqrt(2) - 1)) == sqrt(2) - 1 True >>> acos(inf) +I * Infinity >>> acos(-inf) -I * Infinity >>> acos(inf*i) -I * Infinity >>> acos(-inf*i) +I * Infinity >>> acos(uinf) UnsignedInfinity >>> acos(undefined) Undefined """ res = self._new() if form is None: libcalcium.ca_acos(res, self, self._ctx) elif form == "exponential" or form == "logarithm": libcalcium.ca_acos_logarithm(res, self, self._ctx) else: libcalcium.ca_acos_direct(res, self, self._ctx) return res def erf(self): """ Error function. Examples:: >>> erf(0) 0 >>> erf(1) 0.842701 {a where a = 0.842701 [Erf(1)]} >>> erf(inf) 1 >>> erf(-inf) -1 >>> erf(i*inf) +I * Infinity >>> erf(-i*inf) -I * Infinity >>> erf(uinf) Undefined """ res = self._new() libcalcium.ca_erf(res, self, self._ctx) return res def erfc(self): """ Complementary error function. Examples:: >>> erfc(inf) 0 >>> erfc(-inf) 2 >>> erfc(1000) 1.86004e-434298 {a where a = 1.86004e-434298 [Erfc(1000)]} >>> erfc(i*inf) -I * Infinity >>> erfc(-i*inf) +I * Infinity >>> erfc(sqrt(2)) + erf(sqrt(2)) 1 >>> erfc(uinf) Undefined """ res = self._new() libcalcium.ca_erfc(res, self, self._ctx) return res def erfi(self): """ Imaginary error function. Examples:: >>> erfi(0) 0 >>> erfi(1) 1.65043 {a where a = 1.65043 [Erfi(1)]} >>> erfi(inf) +Infinity >>> erfi(-inf) -Infinity >>> erfi(i*inf) 1.00000*I {a where a = I [a^2+1=0]} >>> erfi(-i*inf) -1.00000*I {-a where a = I [a^2+1=0]} >>> erf(2)**2 + erfi(i*2)**2 0 """ res = self._new() libcalcium.ca_erfi(res, self, self._ctx) return res def gamma(self): """ Gamma function. Examples:: >>> [gamma(n) for n in range(1,11)] [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880] >>> gamma(0) UnsignedInfinity >>> 1 / gamma(0) 0 >>> gamma(0.5) 1.77245 {a where a = 1.77245 [Sqrt(3.14159 {b})], b = 3.14159 [Pi]} >>> gamma(0.5)**2 == pi True >>> pi * gamma(pi) / gamma(pi+1) 1 """ res = self._new() libcalcium.ca_gamma(res, self, self._ctx) return res class ca_mat: """ Python class wrapping the ca_mat_t type for matrices. Examples:: >>> ca_mat(2,3) ca_mat of size 2 x 3 [0, 0, 0] [0, 0, 0] >>> ca_mat([[1,2],[3,4],[5,6]]) ca_mat of size 3 x 2 [1, 2] [3, 4] [5, 6] >>> ca_mat(2, 5, range(10)) ca_mat of size 2 x 5 [0, 1, 2, 3, 4] [5, 6, 7, 8, 9] >>> ca_mat([[1,-2],[2,1]]) * ca_mat([[1,pi],[1,2]]) ca_mat of size 2 x 2 [-1, -0.858407 {a-4 where a = 3.14159 [Pi]}] [ 3, 8.28319 {2*a+2 where a = 3.14159 [Pi]}] A nontrivial calculation:: >>> H = ca_mat([[ca(1)/(i+j+1) for i in range(5)] for j in range(5)]) >>> H ca_mat of size 5 x 5 [ 1, 0.500000 {1/2}, 0.333333 {1/3}, 0.250000 {1/4}, 0.200000 {1/5}] [0.500000 {1/2}, 0.333333 {1/3}, 0.250000 {1/4}, 0.200000 {1/5}, 0.166667 {1/6}] [0.333333 {1/3}, 0.250000 {1/4}, 0.200000 {1/5}, 0.166667 {1/6}, 0.142857 {1/7}] [0.250000 {1/4}, 0.200000 {1/5}, 0.166667 {1/6}, 0.142857 {1/7}, 0.125000 {1/8}] [0.200000 {1/5}, 0.166667 {1/6}, 0.142857 {1/7}, 0.125000 {1/8}, 0.111111 {1/9}] >>> H.trace() 1.78730 {563/315} >>> sum(c*multiplicity for (c, multiplicity) in H.eigenvalues()) 1.78730 {563/315} >>> H.det() 3.74930e-12 {1/266716800000} >>> prod(c**multiplicity for (c, multiplicity) in H.eigenvalues()) 3.74930e-12 {1/266716800000} """ def __init__(self, *args, context=None): if context is None: self._ctx_python = ctx_default else: self._ctx_python = context self._ctx = self._ctx_python._ref self._data = ca_mat_struct() self._ref = ctypes.byref(self._data) if len(args) == 1: val = args[0] if isinstance(val, ca_mat): m = val.nrows() n = val.ncols() libcalcium.ca_mat_init(self, m, n, self._ctx) libcalcium.ca_mat_transfer(self, self._ctx, val, val._ctx) elif isinstance(val, (list, tuple)): m = len(val) n = 0 if m != 0: if not isinstance(val[0], (list, tuple)): raise TypeError("single input to ca_mat must be a list of lists") n = len(val[0]) for i in range(1, m): if len(val[i]) != n: raise ValueError("input rows have different lengths") libcalcium.ca_mat_init(self, m, n, self._ctx) for i in range(m): row = val[i] for j in range(n): x = ca(row[j], context=self._ctx_python) libcalcium.ca_set(libcalcium.ca_mat_entry_ptr(self, i, j, self._ctx), x, self._ctx) else: raise TypeError("cannot create ca_mat from input of type %s" % type(val)) elif len(args) == 2: m, n = args assert m >= 0 assert n >= 0 libcalcium.ca_mat_init(self, m, n, self._ctx) elif len(args) == 3: m, n, entries = args assert m >= 0 assert n >= 0 libcalcium.ca_mat_init(self, m, n, self._ctx) entries = list(entries) if len(entries) != m*n: raise ValueError("list of entries has the wrong length") for i in range(m): for j in range(n): x = ca(entries[i*n + j], context=self._ctx_python) libcalcium.ca_set(libcalcium.ca_mat_entry_ptr(self, i, j, self._ctx), x, self._ctx) else: raise ValueError("ca_mat: expected 1-3 arguments") def __del__(self): libcalcium.ca_mat_clear(self, self._ctx) @property def _as_parameter_(self): return self._ref @staticmethod def from_param(arg): return arg def __bool__(self): t = libcalcium.ca_mat_check_is_zero(self, self._ctx) if t == T_TRUE: return False if t == T_FALSE: return True raise ValueError("unable to decide predicate: is_zero") def _new(self, r, c): return ca_mat(r, c, context=self._ctx_python) def _new_ca(self): return ca(context=self._ctx_python) @staticmethod def operands_with_same_context(a, b): type_a = type(a) type_b = type(b) if type_a is ca_mat and type_b is ca_mat: if a._ctx_python is b._ctx_python: return a, b # which context object to choose? c = a._new(b.nrows(), b.ncols()) libcalcium.ca_mat_transfer(c, c._ctx, b, b._ctx) return a, c return NotImplemented, NotImplemented def __eq__(self, other): """ Examples:: >>> ca_mat([[1,1],[0,1]]) ** 2 == ca_mat([[1,2],[0,1]]) True """ self, other = self.operands_with_same_context(self, other) if self is NotImplemented: return self res = libcalcium.ca_mat_check_equal(self, other, self._ctx) if res == T_TRUE: return True if res == T_FALSE: return False raise NotImplementedError("unable to decide equality") def __ne__(self, other): """ Examples:: >>> ca_mat([[1,1],[0,1]]) ** 2 != ca_mat([[1,3],[0,1]]) True """ self, other = self.operands_with_same_context(self, other) if self is NotImplemented: return self res = libcalcium.ca_mat_check_equal(self, other, self._ctx) if res == T_TRUE: return False if res == T_FALSE: return True raise NotImplementedError("unable to decide equality") def nrows(self): return self._data.r def ncols(self): return self._data.c def entries(self): m = self.nrows() n = self.ncols() L = [None] * (m * n) for i in range(m): for j in range(n): L[i*n + j] = self[i, j] return L def __iter__(self): m = self.nrows() n = self.ncols() for i in range(m): for j in range(n): yield self[i, j] def table(self): m = self.nrows() n = self.ncols() L = self.entries() return [L[i*n : (i+1)*n] for i in range(m)] # supports mpmath conversions tolist = table def __repr__(self): s = "ca_mat of size %i x %i\n" % (self.nrows(), self.ncols()) nrows = self.nrows() ncols = self.ncols() def matrix_to_str(tab): if len(tab) == 0 or len(tab[0]) == 0: return "[]" tab = [[str(c) for c in row] for row in tab] widths = [] for i in range(len(tab[0])): w = max([len(row[i]) for row in tab]) widths.append(w) for i in range(len(tab)): tab[i] = [s.rjust(widths[j]) for j, s in enumerate(tab[i])] tab[i] = "[" + (", ".join(tab[i])) + "]" return "\n".join(tab) return s + matrix_to_str(self.table()) __str__ = __repr__ def _repr_latex_(self): return fexpr(self)._repr_latex_() def __getitem__(self, ij): i, j = ij nrows = self.nrows() ncols = self.ncols() assert 0 <= i < nrows assert 0 <= j < ncols x = self._new_ca() libcalcium.ca_set(x, libcalcium.ca_mat_entry_ptr(self, i, j, self._ctx), self._ctx) return x def __setitem__(self, ij, x): i, j = ij nrows = self.nrows() ncols = self.ncols() assert 0 <= i < nrows assert 0 <= j < ncols x = ca(x, context=self._ctx_python) libcalcium.ca_set(libcalcium.ca_mat_entry_ptr(self, i, j, self._ctx), x, self._ctx) def trace(self): """ The trace of this matrix. Examples:: >>> ca_mat([[1,2],[3,pi]]).trace() 4.14159 {a+1 where a = 3.14159 [Pi]} """ nrows = self.nrows() ncols = self.ncols() if nrows != ncols: raise ValueError("a square matrix is required") res = self._new_ca() libcalcium.ca_mat_trace(res, self, self._ctx) return res def det(self, algorithm=None): """ The determinant of this matrix. Examples:: >>> ca_mat([[1,1-i*pi],[1+i*pi,1]]).det() -9.86960 {-a^2 where a = 3.14159 [Pi], b = I [b^2+1=0]} """ nrows = self.nrows() ncols = self.ncols() if nrows != ncols: raise ValueError("a square matrix is required") res = self._new_ca() if algorithm == "berkowitz": libcalcium.ca_mat_det_berkowitz(res, self, self._ctx) elif algorithm == "lu": if not libcalcium.ca_mat_det_lu(res, self, self._ctx): raise NotImplementedError("unable to compute determinant") elif algorithm == "bareiss" or algorithm == "fflu": if not libcalcium.ca_mat_det_bareiss(res, self, self._ctx): raise NotImplementedError("unable to compute determinant") elif algorithm == "cofactor": if nrows > 4: raise NotImplementedError("unable to compute determinant") libcalcium.ca_mat_det_cofactor(res, self, self._ctx) else: libcalcium.ca_mat_det(res, self, self._ctx) return res def __neg__(self): res = self._new(self.nrows(), self.ncols()) libcalcium.ca_mat_neg(res, self, self._ctx) return res def __pos__(self): res = self._new(self.nrows(), self.ncols()) libcalcium.ca_mat_set(res, self, self._ctx) return res def __add__(self, other): s, t = self.operands_with_same_context(self, other) if s is NotImplemented: try: other = ca(other, context=self._ctx_python) m = self.nrows() n = self.ncols() res = self._new(m, n) libcalcium.ca_mat_add_ca(res, self, other, self._ctx) return res except TypeError: return NotImplemented self, other = s, t m = self.nrows() n = self.ncols() if m != other.nrows() or n != other.ncols(): raise ValueError("incompatible matrix shapes") res = self._new(m, n) libcalcium.ca_mat_add(res, self, other, self._ctx) return res def __sub__(self, other): s, t = self.operands_with_same_context(self, other) if s is NotImplemented: try: other = ca(other, context=self._ctx_python) m = self.nrows() n = self.ncols() res = self._new(m, n) libcalcium.ca_mat_sub_ca(res, self, other, self._ctx) return res except TypeError: return NotImplemented self, other = s, t m = self.nrows() n = self.ncols() if m != other.nrows() or n != other.ncols(): raise ValueError("incompatible matrix shapes") res = self._new(m, n) libcalcium.ca_mat_sub(res, self, other, self._ctx) return res def __mul__(self, other): s, t = self.operands_with_same_context(self, other) if s is NotImplemented: try: other = ca(other, context=self._ctx_python) m = self.nrows() n = self.ncols() res = self._new(m, n) libcalcium.ca_mat_mul_ca(res, self, other, self._ctx) return res except TypeError: return NotImplemented self, other = s, t m = self.nrows() n = self.ncols() k = other.ncols() if n != other.nrows(): raise ValueError("incompatible matrix shapes") res = self._new(m, k) libcalcium.ca_mat_mul(res, self, other, self._ctx) return res def __rmul__(self, other): try: other = ca(other, context=self._ctx_python) m = self.nrows() n = self.ncols() res = self._new(m, n) libcalcium.ca_mat_mul_ca(res, self, other, self._ctx) return res except TypeError: pass return NotImplemented def __truediv__(self, other): try: other = ca(other, context=self._ctx_python) m = self.nrows() n = self.ncols() res = self._new(m, n) libcalcium.ca_mat_div_ca(res, self, other, self._ctx) return res except TypeError: pass return NotImplemented def __pow__(self, other): m = self.nrows() n = self.ncols() assert m == n e = int(other) assert 0 <= e <= sys.maxsize res = self._new(m, m) libcalcium.ca_mat_pow_ui_binexp(res, self, e, self._ctx) return res def conjugate(self): """ Entrywise complex conjugate. >>> ca_mat([[5,1-i]]).conjugate() ca_mat of size 1 x 2 [5, 1.00000 + 1.00000*I {a+1 where a = I [a^2+1=0]}] """ res = self._new(self.nrows(), self.ncols()) libcalcium.ca_mat_conj(res, self, self._ctx) return res conj = conjugate def transpose(self): """ Matrix transpose. >>> ca_mat([[5,1-i]]).transpose() ca_mat of size 2 x 1 [ 5] [1.00000 - 1.00000*I {-a+1 where a = I [a^2+1=0]}] """ res = ca_mat(self.ncols(), self.nrows()) libcalcium.ca_mat_transpose(res, self, self._ctx) return res def conjugate_transpose(self): """ Conjugate matrix transpose. >>> ca_mat([[5,1-i]]).conjugate_transpose() ca_mat of size 2 x 1 [ 5] [1.00000 + 1.00000*I {a+1 where a = I [a^2+1=0]}] """ res = self._new(self.ncols(), self.nrows()) libcalcium.ca_mat_conj_transpose(res, self, self._ctx) return res conj_transpose = conjugate_transpose def charpoly(self): """ Characteristic polynomial of this matrix. >>> ca_mat([[5,pi],[1,-1]]).charpoly() ca_poly of length 3 [-8.14159 {-a-5 where a = 3.14159 [Pi]}, -4, 1] """ m = self.nrows() n = self.ncols() assert m == n res = ca_poly(context=self._ctx_python) libcalcium.ca_mat_charpoly(res, self, self._ctx) return res def eigenvalues(self): """ Eigenvalues of this matrix. Returns a list of (value, multiplicity) pairs. >>> ca_mat(4, 4, range(16)).eigenvalues() [(32.4642 {a+15 where a = 17.4642 [a^2-305=0]}, 1), (-2.46425 {-a+15 where a = 17.4642 [a^2-305=0]}, 1), (0, 2)] >>> ca_mat([[1,pi],[-pi,1]]).eigenvalues()[0] (1.00000 + 3.14159*I {a*b+1 where a = 3.14159 [Pi], b = I [b^2+1=0]}, 1) """ m = self.nrows() n = self.ncols() assert m == n lamda = ca_vec(context=self._ctx_python) exp = ctypes.cast(libflint.flint_malloc(ctypes.sizeof(ctypes.c_ulong) * n), ctypes.POINTER(ctypes.c_ulong)) success = libcalcium.ca_mat_eigenvalues(lamda, exp, self, self._ctx) if not success: libflint.flint_free(exp) raise NotImplementedError("failed to compute eigenvalues") else: res = [(lamda[i], exp[i]) for i in range(len(lamda))] libflint.flint_free(exp) return res def rref(self): """ Reduced row echelon form. >>> ca_mat([[1,2,3],[4,5,6],[7,8,9]]).rref() ca_mat of size 3 x 3 [1, 0, -1] [0, 1, 2] [0, 0, 0] >>> ca_mat([[1,pi,2,pi],[1/pi,3,1/(pi+1),4],[1,1,1,1]]).rref() ca_mat of size 3 x 4 [1, 0, 0, 0.401081 {(a^3-a^2-2*a)/(3*a^2+3*a-2) where a = 3.14159 [Pi]}] [0, 1, 0, 1.35134 {(4*a^2+4*a-2)/(3*a^2+3*a-2) where a = 3.14159 [Pi]}] [0, 0, 1, -0.752416 {(-a^3+a)/(3*a^2+3*a-2) where a = 3.14159 [Pi]}] >>> ca_mat([[1, 0, 0], [0, 1-exp(ca(2)**-10000), 0]]).rref() Traceback (most recent call last): ... NotImplementedError: failed to compute rref """ res = self._new(self.nrows(), self.ncols()) rank = (ctypes.c_long * 1)() if libcalcium.ca_mat_rref(rank, res, self, self._ctx): return res raise NotImplementedError("failed to compute rref") def rank(self): """ Rank of this matrix. >>> ca_mat([[1,2,3],[4,5,6],[7,8,9]]).rank() 2 >>> ca_mat([[1, 0, 0], [0, 1-exp(ca(2)**-10000), 0]]).rank() Traceback (most recent call last): ... NotImplementedError: failed to compute rank """ r = (ctypes.c_long * 1)() if libcalcium.ca_mat_rank(r, self, self._ctx): return int(r[0]) raise NotImplementedError("failed to compute rank") def inv(self): """ Matrix inverse. >>> ca_mat([[1,1],[0,1/pi]]).inv() ca_mat of size 2 x 2 [1, -3.14159 {-a where a = 3.14159 [Pi]}] [0, 3.14159 {a where a = 3.14159 [Pi]}] >>> ca_mat([[1, 1], [2, 2]]).inv() Traceback (most recent call last): ... ZeroDivisionError: singular matrix >>> ca_mat([[1, 0], [0, 1-exp(ca(2)**-10000)]]).inv() Traceback (most recent call last): ... NotImplementedError: failed to prove matrix singular or nonsingular """ n = self.nrows() m = self.ncols() if n != m: raise ValueError("matrix must be square") res = self._new(n, m) invertible = libcalcium.ca_mat_inv(res, self, self._ctx) if invertible == T_TRUE: return res if invertible == T_FALSE: raise ZeroDivisionError("singular matrix") raise NotImplementedError("failed to prove matrix singular or nonsingular") def solve(self, other, algorithm=None): """ Solve linear system (with a nonsingular matrix). >>> ca_mat([[1,2],[3,4]]).solve(ca_mat([[5],[6]])) ca_mat of size 2 x 1 [ -4] [4.50000 {9/2}] >>> ca_mat([[1,1],[2,2]]).solve(ca_mat([[5],[6]])) Traceback (most recent call last): ... ZeroDivisionError: singular matrix >>> ca_mat([[1, 0], [0, 1-exp(ca(2)**-10000)]]).solve(ca_mat([[5],[6]])) Traceback (most recent call last): ... NotImplementedError: failed to prove matrix singular or nonsingular """ self, other = self.operands_with_same_context(self, other) if self is NotImplemented: raise TypeError n = self.nrows() m = self.ncols() if n != m: raise ValueError("matrix must be square") c = other.ncols() if n != other.nrows(): raise ValueError("incompatible matrix shapes") res = self._new(n, c) if algorithm is None: invertible = libcalcium.ca_mat_nonsingular_solve(res, self, other, self._ctx) elif algorithm == "lu": invertible = libcalcium.ca_mat_nonsingular_solve_lu(res, self, other, self._ctx) elif algorithm == "fflu": invertible = libcalcium.ca_mat_nonsingular_solve_fflu(res, self, other, self._ctx) elif algorithm == "adjugate": invertible = libcalcium.ca_mat_nonsingular_solve_adjugate(res, self, other, self._ctx) else: raise ValueError("unknown algorithm") if invertible == T_TRUE: return res if invertible == T_FALSE: raise ZeroDivisionError("singular matrix") raise NotImplementedError("failed to prove matrix singular or nonsingular") def right_kernel(self): """ Returns a basis of the right kernel (nullspace) of *self*. >>> A = ca_mat([[3,4,6],[5,6,7]]) >>> X = A.right_kernel() >>> X ca_mat of size 3 x 1 [ 4] [-4.50000 {-9/2}] [ 1] >>> A * X ca_mat of size 2 x 1 [0] [0] """ res = self._new(0, 0) if libcalcium.ca_mat_right_kernel(res, self, self._ctx): return res raise NotImplementedError("failed to compute right kernel") def diagonalization(self): """ Matrix diagonalization: given a square matrix *self*, returns a diagonal matrix *D* and an invertible matrix *P* such that *self* equals `PDP^{-1}`. Raises *ValueError* if *self* is not diagonalizable. >>> A = ca_mat([[1,2],[3,4]]) >>> D, P = A.diagonalization() >>> D ca_mat of size 2 x 2 [5.37228 {(a+5)/2 where a = 5.74456 [a^2-33=0]}, 0] [ 0, -0.372281 {(-a+5)/2 where a = 5.74456 [a^2-33=0]}] >>> P * D * P.inv() ca_mat of size 2 x 2 [1, 2] [3, 4] A diagonalizable matrix without distinct eigenvalues:: >>> A = ca_mat([[-1,3,-1],[-3,5,-1],[-3,3,1]]) >>> D, P = A.diagonalization() >>> D ca_mat of size 3 x 3 [1, 0, 0] [0, 2, 0] [0, 0, 2] >>> P ca_mat of size 3 x 3 [1, 1, -0.333333 {-1/3}] [1, 1, 0] [1, 0, 1] >>> P * D * P.inv() == A True """ n = self.nrows() m = self.ncols() if n != m: raise ValueError("non-square matrix is not diagonalizable") D = self._new(n, n) P = self._new(n, n) res = libcalcium.ca_mat_diagonalization(D, P, self, self._ctx) if res == T_FALSE: raise ValueError("matrix is not diagonalizable") if res == T_UNKNOWN: raise NotImplementedError("unable to determine if matrix is diagonalizable") return D, P def log(self): """ Matrix logarithm. >>> ca_mat([[4,2],[2,4]]).log().det() == log(2)*(log(2)+log(3)) True >>> ca_mat([[1,1],[0,1]]).log() ca_mat of size 2 x 2 [0, 1] [0, 0] >>> ca_mat([[0,1],[0,0]]).log() Traceback (most recent call last): ... ZeroDivisionError: singular matrix >>> ca_mat([[0,0,1],[0,1,0],[1,0,0]]).log() / (pi*I) ca_mat of size 3 x 3 [ 0.500000 {1/2}, 0, -0.500000 {-1/2}] [ 0, 0, 0] [-0.500000 {-1/2}, 0, 0.500000 {1/2}] >>> ca_mat([[0,0,1],[0,1,0],[1,0,0]]).log().exp() ca_mat of size 3 x 3 [0, 0, 1] [0, 1, 0] [1, 0, 0] """ n = self.nrows() m = self.ncols() if n != m: raise ValueError("matrix must be square") res = self._new(n, m) invertible = libcalcium.ca_mat_log(res, self, self._ctx) if invertible == T_TRUE: return res if invertible == T_FALSE: raise ZeroDivisionError("singular matrix") raise NotImplementedError("unable to compute matrix logarithm") def exp(self): """ Matrix exponential. >>> ca_mat([[1,2],[0,3]]).exp() ca_mat of size 2 x 2 [2.71828 {a where a = 2.71828 [Exp(1)]}, 17.3673 {b^3-b where a = 20.0855 [Exp(3)], b = 2.71828 [Exp(1)]}] [ 0, 20.0855 {a where a = 20.0855 [Exp(3)]}] >>> ca_mat([[1,2],[3,4]]).exp()[0,0] 51.9690 {(-a*c+11*a+b*c+11*b)/22 where a = 215.354 [Exp(5.37228 {(c+5)/2})], b = 0.689160 [Exp(-0.372281 {(-c+5)/2})], c = 5.74456 [c^2-33=0]} >>> ca_mat([[0,0,1],[1,0,0],[0,1,0]]).exp().det() 1 >>> ca_mat([[0,1,0,0,0],[0,0,2,0,0],[0,0,0,3,0],[0,0,0,0,4],[0,0,0,0,0]]).exp() ca_mat of size 5 x 5 [1, 1, 1, 1, 1] [0, 1, 2, 3, 4] [0, 0, 1, 3, 6] [0, 0, 0, 1, 4] [0, 0, 0, 0, 1] This example currently fails (due to failure to compute the exact Jordan decomposition internally): >>> ca_mat([[0,0,1],[0,2,0],[-1,0,0]]).log().exp() Traceback (most recent call last): ... NotImplementedError: unable to compute matrix exponential """ n = self.nrows() m = self.ncols() if n != m: raise ValueError("matrix must be square") res = self._new(n, m) if libcalcium.ca_mat_exp(res, self, self._ctx): return res raise NotImplementedError("unable to compute matrix exponential") def jordan_form(self, transform=False): """ Jordan decomposiion: given a square matrix *self*, returns a block diagonal matrix *J* composed of Jordan blocks and optionally an invertible matrix *P* such that *self* equals `PJP^{-1}`. >>> A = ca_mat([[20,77,59,40], [0,-2,-3,-2], [-10,-35,-23,-15], [2,7,3,1]]) >>> J, P = A.jordan_form(transform=True) >>> P * J * P.inv() ca_mat of size 4 x 4 [ 20, 77, 59, 40] [ 0, -2, -3, -2] [-10, -35, -23, -15] [ 2, 7, 3, 1] >>> A = ca_mat([[log(2), log(3)], [log(4), log(5)]]) >>> J, P = A.jordan_form(transform=True) >>> J[0,0] 2.46769 {(a+b+e)/2 where a = 2.63279 [Sqrt(6.93159 {b^2-2*b*e+8*d*e+e^2})], b = 1.60944 [Log(5)], c = 1.38629 [Log(4)], d = 1.09861 [Log(3)], e = 0.693147 [Log(2)]} >>> P * J * P.inv() == A True """ n = self.nrows() m = self.ncols() if n != m: raise ValueError("non-square matrix") J = self._new(n, n) if transform: P = self._new(n, n) if libcalcium.ca_mat_jordan_form(J, P, self, self._ctx): return J, P else: if libcalcium.ca_mat_jordan_form(J, None, self, self._ctx): return J raise NotImplementedError("unable to compute Jordan decomposition") class ca_vec: """ Python class wrapping the ca_vec_t type for vectors. """ def __init__(self, n=0, context=None): if context is None: self._ctx_python = ctx_default else: self._ctx_python = context self._ctx = self._ctx_python._ref self._data = ca_vec_struct() self._ref = ctypes.byref(self._data) n = int(n) assert n >= 0 libcalcium.ca_vec_init(self, n, self._ctx) def __del__(self): libcalcium.ca_vec_clear(self, self._ctx) @property def _as_parameter_(self): return self._ref @staticmethod def from_param(arg): return arg def __len__(self): return self._data.length def __getitem__(self, i): n = len(self) assert 0 <= i < n x = ca(context=self._ctx_python) libcalcium.ca_set(x, libcalcium.ca_vec_entry_ptr(self, i, self._ctx), self._ctx) return x class ca_poly_vec: def __init__(self, n=0, context=None): if context is None: self._ctx_python = ctx_default else: self._ctx_python = context self._ctx = self._ctx_python._ref self._data = ca_poly_vec_struct() self._ref = ctypes.byref(self._data) n = int(n) assert n >= 0 libcalcium.ca_poly_vec_init(self, n, self._ctx) def __del__(self): libcalcium.ca_poly_vec_clear(self, self._ctx) @property def _as_parameter_(self): return self._ref @staticmethod def from_param(arg): return arg def __len__(self): return self._data.length def __getitem__(self, i): n = len(self) assert 0 <= i < n x = ca_poly(context=self._ctx_python) libcalcium.ca_poly_set(x, ctypes.byref(self._data.entries[i]), self._ctx) return x class ca_poly: """ Python class wrapping the ca_poly_t type for polynomials. """ def __init__(self, val=0, context=None): if context is None: self._ctx_python = ctx_default else: self._ctx_python = context self._ctx = self._ctx_python._ref self._data = ca_poly_struct() self._ref = ctypes.byref(self._data) libcalcium.ca_poly_init(self, self._ctx) if type(val) is ca_poly: libcalcium.ca_poly_transfer(self, self._ctx, val, val._ctx) if type(val) is ca_mat: raise TypeError elif val: try: val = [ca(c, context=self._ctx_python) for c in val] for i in range(len(val)): libcalcium.ca_poly_set_coeff_ca(self, i, val[i], self._ctx) except TypeError: val = ca(val, context=self._ctx_python) libcalcium.ca_poly_set_ca(self, val, self._ctx) def __del__(self): libcalcium.ca_poly_clear(self, self._ctx) @property def _as_parameter_(self): return self._ref @staticmethod def from_param(arg): return arg def __bool__(self): t = libcalcium.ca_poly_check_is_zero(self, self._ctx) if t == T_TRUE: return False if t == T_FALSE: return True raise ValueError("unable to decide predicate: is_zero") def _new(self): return ca_poly(context=self._ctx_python) def _new_ca(self): return ca(context=self._ctx_python) @staticmethod def operands_with_same_context(a, b): type_a = type(a) type_b = type(b) if type_a is ca_poly and type_b is ca_poly: if a._ctx_python is b._ctx_python: return a, b # which context object to choose? c = a._new() libcalcium.ca_poly_transfer(c, c._ctx, b, b._ctx) return a, c if type_a is ca_poly: try: b = ca_poly(b, context=a._ctx_python) except TypeError: return NotImplemented, NotImplemented return a, b else: try: a = ca_poly(a, context=b._ctx_python) except TypeError: return NotImplemented, NotImplemented return a, b return NotImplemented, NotImplemented def __eq__(self, other): """ Examples:: >>> ca_poly([1,1]) ** 2 == ca_poly([1,2,1]) True """ self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: return self res = libcalcium.ca_poly_check_equal(self, other, self._ctx) if res == T_TRUE: return True if res == T_FALSE: return False raise NotImplementedError("unable to decide equality") def __ne__(self, other): """ Examples:: >>> ca_poly([1,1]) ** 2 != ca_poly([1,3,1]) True """ self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: return self res = libcalcium.ca_poly_check_equal(self, other, self._ctx) if res == T_TRUE: return False if res == T_FALSE: return True raise NotImplementedError("unable to decide equality") def __len__(self): return self._data.length def __repr__(self): n = len(self) s = "ca_poly of length %i\n" % n s += str([self[i] for i in range(n)]) return s __str__ = __repr__ def _repr_latex_(self): return fexpr(self)._repr_latex_() def __getitem__(self, i): n = len(self) assert 0 <= i < n x = self._new_ca() libcalcium.ca_set(x, libcalcium.ca_poly_coeff_ptr(self, i, self._ctx), self._ctx) return x def __neg__(self): res = self._new() libcalcium.ca_poly_neg(res, self, self._ctx) return res def __pos__(self): res = self._new() libcalcium.ca_poly_set(res, self, self._ctx) return res def __add__(self, other): self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_poly_add(res, self, other, self._ctx) return res __radd__ = __add__ def __sub__(self, other): self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() res = ca_poly() libcalcium.ca_poly_sub(res, self, other, self._ctx) return res def __rsub__(self, other): self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_poly_sub(res, other, self, self._ctx) return res def __mul__(self, other): self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_poly_mul(res, self, other, self._ctx) return res __rmul__ = __mul__ def __truediv__(self, other): try: other = ca(other, self._ctx_python) except (TypeError, ValueError): return NotImplemented res = self._new() # todo: catch division by zero libcalcium.ca_poly_div_ca(res, self, other, self._ctx) return res def __floordiv__(self, other): self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() if not libcalcium.ca_poly_div(res, self, other, self._ctx): raise ValueError("failed polynomial division: unable to prove leading coefficient nonzero") return res def __mod__(self, other): self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() if not libcalcium.ca_poly_rem(res, self, other, self._ctx): raise ValueError("failed polynomial division: unable to prove leading coefficient nonzero") return res def __divmod__(self, other): self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: return self res1 = self._new() res2 = self._new() if not libcalcium.ca_poly_divrem(res1, res2, self, other, self._ctx): raise ValueError("failed polynomial division: unable to prove leading coefficient nonzero") return res1, res2 def __pow__(self, other): e = int(other) assert e >= 0 and e * len(self) <= sys.maxsize res = self._new() libcalcium.ca_poly_pow_ui(res, self, e, self._ctx) return res def mul_series(self, other, n): self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_poly_mullow(res, self, other, n, self._ctx) return res def div_series(self, other, n): self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: return self res = self._new() libcalcium.ca_poly_div_series(res, self, other, n, self._ctx) return res def inv_series(self, n): """ Power series inverse truncated to length n. Examples:: >>> ca_poly([1,2,3]).inv_series(10) ca_poly of length 10 [1, -2, 1, 4, -11, 10, 13, -56, 73, 22] >>> ca_poly([sqrt(2), 1, 2]).inv_series(5).inv_series(5) ca_poly of length 3 [1.41421 {a where a = 1.41421 [a^2-2=0]}, 1, 2] >>> ca_poly([]).inv_series(3) ca_poly of length 3 [UnsignedInfinity, Undefined, Undefined] >>> ca_poly([0,1,2]).inv_series(3) ca_poly of length 3 [UnsignedInfinity, Undefined, Undefined] >>> ca_poly([inf,1,2]).inv_series(3) ca_poly of length 3 [Undefined, Undefined, Undefined] """ res = self._new() libcalcium.ca_poly_inv_series(res, self, n, self._ctx) return res def log_series(self, n): """ Power series logarithm truncated to length n. Examples:: >>> ca_poly([1,1]).log_series(4) ca_poly of length 4 [0, 1, -0.500000 {-1/2}, 0.333333 {1/3}] >>> ca_poly([2,1]).log_series(4) ca_poly of length 4 [0.693147 {a where a = 0.693147 [Log(2)]}, 0.500000 {1/2}, -0.125000 {-1/8}, 0.0416667 {1/24}] >>> ca_poly([-2,2,3]).log_series(5).exp_series(5) ca_poly of length 3 [-2, 2, 3] >>> ca_poly([0,1]).log_series(3) ca_poly of length 3 [-Infinity, Undefined, Undefined] >>> ca_poly([inf,1]).log_series(3) ca_poly of length 3 [Undefined, Undefined, Undefined] """ res = self._new() libcalcium.ca_poly_log_series(res, self, n, self._ctx) return res def exp_series(self, n): """ Power series exponential truncated to length n. Examples:: >>> ca_poly([0,1]).exp_series(4) ca_poly of length 4 [1, 1, 0.500000 {1/2}, 0.166667 {1/6}] >>> ca_poly([1,-0.5]).exp_series(2) ca_poly of length 2 [2.71828 {a where a = 2.71828 [Exp(1)]}, -1.35914 {(-a)/2 where a = 2.71828 [Exp(1)]}] >>> ca_poly([inf]).exp_series(3) ca_poly of length 3 [Undefined, Undefined, Undefined] >>> ca_poly([unknown]).exp_series(3) ca_poly of length 3 [Unknown, Unknown, Unknown] """ res = self._new() libcalcium.ca_poly_exp_series(res, self, n, self._ctx) return res def atan_series(self, n): """ Power series inverse tangent truncated to length n. >>> ca_poly([0,1]).atan_series(6) ca_poly of length 6 [0, 1, 0, -0.333333 {-1/3}, 0, 0.200000 {1/5}] >>> ca_poly([1,1]).atan_series(4) ca_poly of length 4 [0.785398 {(a)/4 where a = 3.14159 [Pi]}, 0.500000 {1/2}, -0.250000 {-1/4}, 0.0833333 {1/12}] >>> f = ca_poly([2,3,4]) >>> 2*f.atan_series(5) - ((2*f).div_series(1-f**2, 5)).atan_series(5) == pi True >>> ca_poly([0]).atan_series(3) ca_poly of length 0 [] >>> ca_poly([i,1]).atan_series(3) ca_poly of length 3 [+I * Infinity, Undefined, Undefined] >>> ca_poly([-i,1]).atan_series(3) ca_poly of length 3 [-I * Infinity, Undefined, Undefined] >>> ca_poly([unknown,1]).atan_series(3) ca_poly of length 3 [Unknown, Unknown, Unknown] """ res = self._new() libcalcium.ca_poly_atan_series(res, self, n, self._ctx) return res def __call__(self, other): """ Evaluation or composition. >>> ca_poly([1,2,3])(pi) 36.8920 {3*a^2+2*a+1 where a = 3.14159 [Pi]} >>> ca_poly([1,2,3])(ca_poly([3,2,1])) ca_poly of length 5 [34, 40, 32, 12, 3] """ if type(other) is not ca_poly or other._ctx_python is not self._ctx_python: try: other = ca(other, context=self._ctx_python) res = self._new_ca() libcalcium.ca_poly_evaluate(res, self, other, self._ctx) return res except TypeError: pass try: other = ca_poly(other, context=self._ctx_python) except TypeError: other = ca_mat(other, context=self._ctx_python) assert other.nrows() == other.ncols() res = other._new(other.nrows(), other.ncols()) libcalcium.ca_mat_ca_poly_evaluate(res, self, other, self._ctx) return res res = self._new() libcalcium.ca_poly_compose(res, self, other, self._ctx) return res def gcd(self, other): """ Polynomial GCD. Examples:: >>> x = ca_poly([0,1]); (x+1).gcd(x-1) ca_poly of length 1 [1] >>> x = ca_poly([0,1]); (x**2 + pi**2).gcd(x+i*pi) ca_poly of length 2 [3.14159*I {a*b where a = 3.14159 [Pi], b = I [b^2+1=0]}, 1] """ self, other = ca_poly.operands_with_same_context(self, other) if self is NotImplemented: raise TypeError res = self._new() if not libcalcium.ca_poly_gcd(res, self, other, self._ctx): raise ValueError("failed polynomial gcd") return res def roots(self): """ Roots of this polynomial. Returns a list of (root, multiplicity) pairs. >>> ca_poly([2,11,20,12]).roots() [(-0.666667 {-2/3}, 1), (-0.500000 {-1/2}, 2)] """ n = len(self) roots = ca_vec(context=self._ctx_python) exp = ctypes.cast(libflint.flint_malloc(ctypes.sizeof(ctypes.c_ulong) * n), ctypes.POINTER(ctypes.c_ulong)) success = libcalcium.ca_poly_roots(roots, exp, self, self._ctx) if not success: libflint.flint_free(exp) raise ValueError("failed to compute roots") else: res = [(roots[i], exp[i]) for i in range(len(roots))] libflint.flint_free(exp) return res def factor_squarefree(self): """ Squarefree factorization of this polynomial Returns (lc, L) where L is a list of (factor, multiplicity) pairs. >>> ca_poly([9,6,7,-28,12]).factor_squarefree() (12, [(ca_poly of length 3 [0.333333 {1/3}, 0.666667 {2/3}, 1], 1), (ca_poly of length 2 [-1.50000 {-3/2}, 1], 2)]) """ n = len(self) lc = self._new_ca() fac = ca_poly_vec(context=self._ctx_python) exp = ctypes.cast(libflint.flint_malloc(ctypes.sizeof(ctypes.c_ulong) * n), ctypes.POINTER(ctypes.c_ulong)) success = libcalcium.ca_poly_factor_squarefree(lc, fac, exp, self, self._ctx) if not success: libflint.flint_free(exp) raise ValueError("failed to compute factors") else: res = [(fac[i], exp[i]) for i in range(len(fac))] libflint.flint_free(exp) return lc, res def squarefree_part(self): """ Squarefree part of this polynomial. >>> ca_poly([9,6,7,-28,12]).squarefree_part() ca_poly of length 4 [-0.500000 {-1/2}, -0.666667 {-2/3}, -0.833333 {-5/6}, 1] """ res = self._new() if not libcalcium.ca_poly_squarefree_part(res, self, self._ctx): raise ValueError("failed to compute squarefree part") return res def integral(self): """ Integral of this polynomial. >>> ca_poly([1,1,1,1]).integral() ca_poly of length 5 [0, 1, 0.500000 {1/2}, 0.333333 {1/3}, 0.250000 {1/4}] """ res = self._new() libcalcium.ca_poly_integral(res, self, self._ctx) return res def derivative(self): """ Derivative of this polynomial. >>> ca_poly([1,1,1,1]).derivative() ca_poly of length 3 [1, 2, 3] """ res = self._new() libcalcium.ca_poly_derivative(res, self, self._ctx) return res def monic(self): """ Make this polynomial monic. >>> ca_poly([1,2,3]).monic() ca_poly of length 3 [0.333333 {1/3}, 0.666667 {2/3}, 1] >>> ca_poly().monic() Traceback (most recent call last): ... ValueError: failed to make monic """ res = self._new() if not libcalcium.ca_poly_make_monic(res, self, self._ctx): raise ValueError("failed to make monic") return res def is_proper(self): """ Checks if this polynomial definitely has finite coefficients and that the leading coefficient is provably nonzero. >>> ca_poly([]).is_proper() True >>> ca_poly([1,2,3]).is_proper() True >>> ca_poly([1,2,1-exp(ca(2)**-10000)]).is_proper() False >>> ca_poly([inf]).is_proper() False """ if libcalcium.ca_poly_is_proper(self, self._ctx): return True return False def degree(self): """ Degree of this polynomial. >>> ca_poly([1,2,3]).degree() 2 >>> ca_poly().degree() -1 >>> ca_poly([1,2,1-exp(ca(2)**-10000)]).degree() Traceback (most recent call last): ... NotImplementedError: unable to determine degree """ if self.is_proper(): return len(self) - 1 raise NotImplementedError("unable to determine degree") def re(x): if type(x) != ca: x = ca(x) return x.re() def im(x): if type(x) != ca: x = ca(x) return x.im() def sgn(x): if type(x) != ca: x = ca(x) return x.sgn() def sign(x): if type(x) != ca: x = ca(x) return x.sign() def csgn(x): if type(x) != ca: x = ca(x) return x.csgn() def arg(x): if type(x) != ca: x = ca(x) return x.arg() def floor(x): if type(x) != ca: x = ca(x) return x.floor() def ceil(x): if type(x) != ca: x = ca(x) return x.ceil() def conj(x): if type(x) != ca: x = ca(x) return x.conj() def conjugate(x): if type(x) != ca: x = ca(x) return x.conjugate() def sqrt(x): if type(x) != ca: x = ca(x) return x.sqrt() def log(x): if type(x) != ca: x = ca(x) return x.log() def exp(x): if type(x) != ca: x = ca(x) return x.exp() def erf(x): if type(x) != ca: x = ca(x) return x.erf() def erfc(x): if type(x) != ca: x = ca(x) return x.erfc() def erfi(x): if type(x) != ca: x = ca(x) return x.erfi() def gamma(x): if type(x) != ca: x = ca(x) return x.gamma() def fac(x): """ Alias for gamma(x+1). Examples:: >>> fac(10) 3.62880e+6 {3628800} """ if type(x) != ca: x = ca(x) return (x+1).gamma() def cos(x, form=None): if type(x) != ca: x = ca(x) return x.cos(form=form) def sin(x, form=None): if type(x) != ca: x = ca(x) return x.sin(form=form) def tan(x, form=None): if type(x) != ca: x = ca(x) return x.tan(form=form) def atan(x, form=None): if type(x) != ca: x = ca(x) return x.atan(form=form) def asin(x, form=None): if type(x) != ca: x = ca(x) return x.asin(form=form) def acos(x, form=None): if type(x) != ca: x = ca(x) return x.acos(form=form) def cosh(x): """ The hyperbolic cosine function is not yet implemented in Calcium. This placeholder function evaluates the hyperbolic cosine function using exponentials. Examples:: >>> cosh(1) 1.54308 {(a^2+1)/(2*a) where a = 2.71828 [Exp(1)]} """ y = exp(x) return (y + 1/y)/2 def sinh(x): """ The hyperbolic sine function is not yet implemented in Calcium. This placeholder function evaluates the hyperbolic sine function using exponentials. Examples:: >>> sinh(1) 1.17520 {(a^2-1)/(2*a) where a = 2.71828 [Exp(1)]} """ y = exp(x) return (y - 1/y)/2 def tanh(x): """ The hyperbolic tangent function is not yet implemented in Calcium. This placeholder function evaluates the hyperbolic tangent function using exponentials. Examples:: >>> tanh(1) 0.761594 {(a^2-1)/(a^2+1) where a = 2.71828 [Exp(1)]} """ return sinh(x)/cosh(x) #class allocated_c_char_p(ctypes.c_char_p): # def __del__(self): # libflint.flint_free(self) libflint.flint_malloc.restype = ctypes.c_void_p libflint.flint_free.argtypes = (ctypes.c_void_p,) libflint.fmpz_set_str.argtypes = ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int libflint.fmpz_get_str.argtypes = ctypes.c_char_p, ctypes.c_int, ctypes.POINTER(_fmpz_struct) libflint.fmpz_get_str.restype = ctypes.c_void_p libcalcium.fexpr_builtin_name.restype = ctypes.c_char_p libcalcium.fexpr_set_symbol_str.argtypes = ctypes.c_void_p, ctypes.c_char_p libcalcium.fexpr_get_str.restype = ctypes.c_void_p libcalcium.fexpr_get_str_latex.restype = ctypes.c_void_p libcalcium.fexpr_set_si.argtypes = fexpr, ctypes.c_long libcalcium.fexpr_set_d.argtypes = fexpr, ctypes.c_double libcalcium.fexpr_set_re_im_d.argtypes = fexpr, ctypes.c_double, ctypes.c_double libcalcium.fexpr_get_decimal_str.restype = ctypes.c_void_p libcalcium.qqbar_set_si.argtypes = qqbar, ctypes.c_long libcalcium.qqbar_set_d.argtypes = qqbar, ctypes.c_double libcalcium.qqbar_set_re_im_d.argtypes = qqbar, ctypes.c_double, ctypes.c_double libcalcium.qqbar_get_str_nd.restype = ctypes.c_void_p libcalcium._qqbar_vec_init.restype = ctypes.POINTER(qqbar_struct) libcalcium.ca_mat_entry_ptr.restype = ctypes.POINTER(ca_mat_struct) libcalcium.ca_vec_entry_ptr.restype = ctypes.POINTER(ca_vec_struct) libcalcium.ca_poly_coeff_ptr.restype = ctypes.POINTER(ca_struct) libcalcium.ca_set_si.argtypes = ca, ctypes.c_long, ca_ctx libcalcium.ca_set_d.argtypes = ca, ctypes.c_double, ca_ctx libcalcium.ca_set_d_d.argtypes = ca, ctypes.c_double, ctypes.c_double, ca_ctx libcalcium.ca_get_str.argtypes = ca, ca_ctx libcalcium.ca_get_str.restype = ctypes.c_void_p libcalcium.ca_get_decimal_str.restype = ctypes.c_void_p libcalcium.ca_ctx_set_option.argtypes = ca_ctx, ctypes.c_long, ctypes.c_long libcalcium.ca_ctx_get_option.restype = ctypes.c_long i = j = ca.i() pi = ca.pi() euler = ca.euler() e = ca(1).exp() inf = ca.inf() uinf = ca.uinf() undefined = ca.undefined() unknown = ca.unknown() fexpr.inject() I = NumberI E = NumberE def prod(s): res = ca(1) for x in s: res *= x return res def gd(x): return 2*atan(exp(x))-pi/2 def test_floor_ceil(): assert floor(sqrt(2)) == 1 assert ceil(sqrt(2)) == 2 def test_power_identities(): assert (sqrt(2)**sqrt(2))**sqrt(2) == 2 assert (sqrt(-2)**sqrt(2))**sqrt(2) == -2 assert (sqrt(3)**sqrt(3))**sqrt(3) == 3*sqrt(3) assert sqrt(-pi)**2 == -pi def test_log(): assert log(1+pi) - log(pi) - log(1+1/pi) == 0 assert log(log(-log(log(exp(exp(-exp(exp(3)))))))) == 3 def test_exp(): assert exp(pi*i) + 1 == 0 assert exp(pi*i) == -1 assert exp(log(2)*log(3)) > 2 assert e**2 == exp(2) def test_erf(): assert erf(2*log(sqrt(ca(1)/2-sqrt(2)/4))+log(4)) - erf(log(2-sqrt(2))) == 0 assert 1-erf(pi)-erfc(pi) == 0 assert erf(sqrt(2))**2 + erfi(sqrt(-2))**2 == 0 def test_gudermannian(): assert sin(gd(1)) == tanh(1) assert tan(gd(1)) == sinh(1) assert sin(gd(sqrt(2))) == tanh(sqrt(2)) assert tan(gd(1)/2) - tanh(ca(1)/2) == 0 def test_gamma(): assert gamma(1) == 1 assert gamma(0.5) == sqrt(pi) assert 1/gamma(0) == 0 assert gamma(sqrt(2)*sqrt(3)) == gamma(sqrt(6)) assert gamma(pi+1)/gamma(pi) == pi assert gamma(pi)/gamma(pi-1) == pi-1 assert log(gamma(pi+1)) - log(gamma(pi)) - log(pi) == 0 assert log(gamma(-pi+1)) - log(gamma(-pi)) - log(pi) == pi * i def test_conversions(): assert ca(qqbar(sqrt(2))) == sqrt(2) assert ca(fexpr(ca(Sqrt(2)))) == sqrt(2) def test_notebook_examples(): # algebraic number identity I = NumberI lhs = Sqrt(36 + 3*(-54+35*I*Sqrt(3))**Div(1,3)*3**Div(1,3) + \ 117/(-162+105*I*Sqrt(3))**Div(1,3))/3 + \ Sqrt(5)*(1296*I+840*Sqrt(3)-35*3**Div(5,6)*(-54+35*I*Sqrt(3))**Div(1,3)-\ 54*I*(-162+105*I*Sqrt(3))**Div(1,3)+13*I*(-162+105*I*Sqrt(3))**Div(2,3))/(5*(162*I+105*Sqrt(3))) rhs = Sqrt(5) + Sqrt(7) assert qqbar(lhs) == qqbar(rhs) assert ca(lhs) == ca(rhs) assert fexpr(ca(lhs) - ca(rhs)) == fexpr(0) # misc assert fexpr(exp(pi) * exp(-pi + log(2))) == fexpr(2) assert i**i - exp(pi / ((sqrt(-2)**sqrt(2)) ** sqrt(2))) == 0 assert log(sqrt(2)+sqrt(3)) / log(5 + 2*sqrt(6)) == ca(1)/2 assert ca(10)**-30 < (640320**3 + 744)/exp(pi*sqrt(163)) - 1 < ca(10)**-29 A = ca_mat([[5, pi], [1, -1]])**4 assert A.charpoly()(A) == ca_mat([[0,0],[0,0]]) # comparison with higher precision ctx = ca_ctx(prec_limit=65536) eps = ca(10, context=ctx) ** (-10000) assert (exp(eps) == 1) == False def test_qqbar_misc(): x = (1 + 100*qqbar(2)**(-1000)).root(100) y = (1 + 101*qqbar(2)**(-1000)).root(101) assert x > y def test_context_switch(): ctx2 = ca_ctx() a = ca(3) b = ca(3, context=ctx2) assert a == b a = exp(a) b = exp(b) assert a == b assert a._ctx_python is not b._ctx_python assert a - b == 0 assert a + b == 2 * a assert b + a == 2 * a assert a + b == 2 * b assert b + a == 2 * b A = ca_mat([[b]]) B = ca_mat([[a]], context=ctx2) assert A._ctx_python is not B._ctx_python assert A == B assert A + B == 2 * A assert A + B == 2 * B assert B + A == 2 * A assert B + A == 2 * B assert A.det() == B.det() assert A[0,0] == B[0,0] A = ca_poly([b]) B = ca_poly([a], context=ctx2) assert A._ctx_python is not B._ctx_python assert A == B assert A + B == 2 * A assert B + A == 2 * A assert A + B == 2 * B assert B + A == 2 * B assert A[0] == B[0] def test_improved_zero_recognition(): assert sqrt(2)*(1+i)/2 * pi - exp(pi*i/4) * pi == 0 assert (sqrt(3) + i)/2 * pi - exp(pi*i/6) * pi == 0 assert arg(sqrt(-pi*i)) == -pi/4 assert (pi + sqrt(2) + sqrt(3)) / (pi + sqrt(5 + 2*sqrt(6))) == 1 assert log(1/exp(sqrt(2)+1)) == -sqrt(2)-1 assert abs(exp(sqrt(1+i))) == exp(re(sqrt(1+i))) assert tan(pi*sqrt(2))*tan(pi*sqrt(3)) == (cos(pi*sqrt(5-2*sqrt(6))) - cos(pi*sqrt(5+2*sqrt(6))))/(cos(pi*sqrt(5-2*sqrt(6))) + cos(pi*sqrt(5+2*sqrt(6)))) assert log(exp(1j) / exp(-1j)) == 2*i v = cos(acos(sqrt(2) - sqrt(3))/3) assert 1 - 90*v**2 + 321*v**4 - 592*v**6 + 864*v**8 - 768*v**10 + 256*v**12 == 0 def expect_not_implemented(f): try: v = f() assert v except NotImplementedError: return raise AssertionError expect_not_implemented(lambda: acos(cos(1)) == 1) expect_not_implemented(lambda: acos(cos(sqrt(2) - 1)) == sqrt(2) - 1) expect_not_implemented(lambda: tan(sqrt(pi*2))*tan(sqrt(pi*3)) == \ (cos(sqrt(pi*(5-2*sqrt(6)))) - cos(sqrt(pi*(5+2*sqrt(6)))))/(cos(sqrt(pi*(5-2*sqrt(6)))) + cos(sqrt(pi*(5+2*sqrt(6)))))) expect_not_implemented(lambda: sqrt(exp(2*sqrt(2)) + exp(-2*sqrt(2)) - 2) == (exp(2*sqrt(2))-1)/sqrt(exp(2*sqrt(2)))) # Some examples from Stoutemyer z = pi assert str(i*((3-5*1j)*z+1)/(((5+3j)*z+1j)*z)) == "0.318310 {(1)/(a) where a = 3.14159 [Pi], b = I [b^2+1=0]}" assert str(ca(-1)**(1/8.) * sqrt(i+1) / ca(2)**(3/4.) + i*exp(i*pi/2)) == "-0.500000 + 0.500000*I {(a-1)/2 where a = I [a^2+1=0]}" assert sin(2*atan(z)) + (15*sqrt(3)+26)**(ca(1)/3) == 2*z/(z**2+1) + sqrt(3) + 2 def test_trigonometric(): def expect_not_implemented(f): try: v = f() assert v except NotImplementedError: return raise AssertionError a = 1+sqrt(2) b = 2+sqrt(2) xsin = sin; xcos = cos; xtan = tan assert xsin(a)**2 + xcos(a)**2 == 1 assert xsin(-a)**2 + xcos(a)**2 == 1 assert xsin(a) == -xsin(-a) assert xcos(a) == xcos(-a) assert xtan(a) == -xtan(-a) assert xsin(a+2*pi) == xsin(a) assert xcos(a+2*pi) == xcos(a) assert xtan(a+pi) == xtan(a) assert xsin(a+pi) == -xsin(a) assert xcos(a+pi) == -xcos(a) assert xtan(a+pi/2) == -1/xtan(a) assert xsin(a+pi/2) == xcos(a) assert xcos(a+pi/2) == -xsin(a) assert xsin(a-pi/2) == -xcos(a) assert xcos(a-pi/2) == xsin(a) assert xtan(a+pi/4) == (xtan(a)+1)/(1-xtan(a)) assert xtan(a-pi/4) == (xtan(a)-1)/(1+xtan(a)) assert xsin(pi/2 - a) == xcos(a) assert xcos(pi/2 - a) == xsin(a) assert xtan(pi/2 - a) == 1 / xtan(a) assert xsin(pi - a) == xsin(a) assert xcos(pi - a) == -xcos(a) assert xtan(pi - a) == -tan(a) assert xsin(2*pi - a) == -xsin(a) assert xcos(2*pi - a) == xcos(a) assert xsin(a+b) == xsin(a)*xcos(b) + xcos(a)*xsin(b) assert xsin(a-b) == xsin(a)*xcos(b) - xcos(a)*xsin(b) assert xcos(a+b) == xcos(a)*xcos(b) - xsin(a)*xsin(b) assert xcos(a-b) == xcos(a)*xcos(b) + xsin(a)*xsin(b) assert xtan(a+b) == (xtan(a)+xtan(b)) / (1 - xtan(a)*xtan(b)) assert xtan(a-b) == (xtan(a)-xtan(b)) / (1 + xtan(a)*xtan(b)) assert xsin(2*a) == 2*xsin(a)*xcos(a) assert xsin(2*a) == 2*xtan(a)/(1+xtan(a)**2) assert xcos(2*a) == xcos(a)**2 - xsin(a)**2 assert xcos(2*a) == 2*xcos(a)**2 - 1 assert xcos(2*a) == 1 - 2*xsin(a)**2 assert xcos(2*a) == (1 - xtan(a)**2) / (1 + xtan(a)**2) assert xtan(2*a) == (2*xtan(a)) / (1 - xtan(a)**2) assert xsin(3*a) == 3*xsin(a) - 4*xsin(a)**3 assert xcos(3*a) == 4*xcos(a)**3 - 3*xcos(a) assert xtan(3*a) == (3*xtan(a) - xtan(a)**3) / (1 - 3*xtan(a)**2) assert xsin(a/2)**2 == (1-xcos(a))/2 assert xcos(a/2)**2 == (1+xcos(a))/2 assert xtan((a-b)/2) == (xsin(a) - xsin(b)) / (xcos(a) + xcos(b)) assert 2*xcos(a)*xcos(b) == xcos(a-b) + xcos(a+b) assert 2*xsin(a)*xsin(b) == xcos(a-b) - xcos(a+b) assert 2*xsin(a)*xcos(b) == xsin(a+b) + xsin(a-b) assert 2*xcos(a)*xsin(b) == xsin(a+b) - xsin(a-b) assert xsin(a) + xsin(b) == 2*xsin((a+b)/2)*xcos((a-b)/2) assert xsin(a) - xsin(b) == 2*xsin((a-b)/2)*xcos((a+b)/2) assert xcos(a) + xcos(b) == 2*xcos((a+b)/2)*xcos((a-b)/2) assert xcos(a) - xcos(b) == -2*xsin((a+b)/2)*xsin((a-b)/2) assert xsin(a) == sqrt(1 - xcos(a)**2) for N in range(1,17): assert sum(cos(n*a) for n in range(1,N+1)) == sin((N+0.5)*a)/(2*sin(a/2)) - 0.5 assert xcos(a) == -sqrt(1 - xsin(a)**2) assert xsin(a/2) == sqrt((1-xcos(a))/2) expect_not_implemented(lambda: xsin(3*a) == 4*xsin(a)*xsin(pi/3-a)*xsin(pi/3+a)) assert xtan((a+b)/2) == (xsin(a) + xsin(b)) / (xcos(a) + xcos(b)) assert xtan((a+b)/2) == (xsin(a) + xsin(b)) / (xcos(a) + xcos(b)) assert xtan(a)*xtan(b) == ((xcos(a-b)-xcos(a+b))/(xcos(a-b)+xcos(a+b))) def test_comparisons(): assert inf >= inf assert inf >= -inf assert inf >= 3 assert not -inf >= inf assert -inf >= -inf assert not -inf >= 3 assert not inf > inf assert inf > -inf assert inf > 3 assert not -inf > inf assert not -inf > -inf assert not -inf >= 3 assert inf <= inf assert not inf <= -inf assert not inf <= 3 assert -inf <= inf assert -inf <= -inf assert -inf <= 3 assert not inf < inf assert not inf < -inf assert not inf < 3 assert -inf < inf assert not -inf < -inf assert -inf < 3 for a in [inf, -inf, ca(3)]: for b in [uinf, undefined, inf*i, 2+i]: assert not a < b assert not a <= b assert not a > b assert not a >= b assert not b < a assert not b <= a assert not b > a assert not b >= a assert pi + sqrt(2) + sqrt(3) <= pi + sqrt(5 + 2 * sqrt(6)) assert not pi + sqrt(2) + sqrt(3) < pi + sqrt(5 + 2 * sqrt(6)) assert pi + sqrt(2) + sqrt(3) >= pi + sqrt(5 + 2 * sqrt(6)) assert not pi + sqrt(2) + sqrt(3) > pi + sqrt(5 + 2 * sqrt(6)) assert pi + exp(-1000) > pi assert pi - exp(-1000) < pi assert sin(1) < 1 assert sin(1) <= sqrt(1 - cos(1)**2) assert asin(ca(1)/10) > ca(1)/10 def test_xfail(): # Test some simplifications that are known not to work yet. # When a case starts working, we will get a test failure so we can # catch it and add it to the working tests def gd(x): return 2*atan(exp(x))-pi/2 def expect_error(f): try: f() except ValueError: return raise AssertionError # expect_error(lambda: tan(gd(1)/2) - tanh(ca(1)/2) == 0) def test_latex(): from pyca_test import test_latex test_latex.test_latex(fexpr) def latex_test_report(): from pyca_test import test_latex test_latex.latex_report(fexpr) if __name__ == "__main__": from time import time print("Testing pycalcium_ctypes") print("----------------------------------------------------------") for fname in dir(): if fname.startswith("test_"): print(fname + "...", end="") t1 = time() globals()[fname]() t2 = time() print("PASS", end=" ") print("%.2f" % (t2-t1)) print("----------------------------------------------------------") import doctest doctest.testmod(verbose=True) print("----------------------------------------------------------") calcium-0.4.1/pycalcium/pyca_test/000077500000000000000000000000001407704557200171255ustar00rootroot00000000000000calcium-0.4.1/pycalcium/pyca_test/__init__.py000066400000000000000000000000001407704557200212240ustar00rootroot00000000000000calcium-0.4.1/pycalcium/pyca_test/test_latex.py000066400000000000000000001237331407704557200216640ustar00rootroot00000000000000latex_test_cases = [ ("""f(0)""", "f(0)"), ("""f("Hello, world!")""", "f(\\text{``Hello, world!''})"), ("f", r"f"), ("f_", r"f"), ("f_(0)", r"f_{0}"), ("f()", r"f()"), ("Add(Add(Add(f(a, b), c_(n)), f_(x, y)), f_())", r"f(a, b) + c_{n} + f_{x, y} + f_{}"), ("f(alpha, beta, chi, delta, ell, epsilon, eta)", r"f(\alpha, \beta, \chi, \delta, \ell, \varepsilon, \eta)"), ("f(gamma, iota, kappa, lamda, mu, nu, omega, phi)", r"f(\gamma, \iota, \kappa, \lambda, \mu, \nu, \omega, \phi)"), ("f(pi, rho, sigma, tau, theta, varphi, vartheta, xi, zeta)", r"f(\pi, \rho, \sigma, \tau, \theta, \varphi, \vartheta, \xi, \zeta)"), ("f(Delta, GreekGamma, GreekPi, Lamda, Omega, Phi, Psi, Sigma, Theta, Xi)", r"f(\Delta, \Gamma, \Pi, \Lambda, \Omega, \Phi, \Psi, \Sigma, \Theta, \Xi)"), ("f(alpha_, beta_, chi_, delta_, ell_, epsilon_, eta_)", r"f(\alpha, \beta, \chi, \delta, \ell, \varepsilon, \eta)"), ("f(gamma_, iota_, kappa_, lamda_, mu_, nu_, omega_, phi_)", r"f(\gamma, \iota, \kappa, \lambda, \mu, \nu, \omega, \phi)"), ("f(pi_, rho_, sigma_, tau_, theta_, varphi_, vartheta_, xi_, zeta)", r"f(\pi, \rho, \sigma, \tau, \theta, \varphi, \vartheta, \xi, \zeta)"), ("f(Delta_, GreekGamma_, GreekPi_, Lamda_, Omega_, Phi_, Psi_, Sigma_, Theta_, Xi_)", r"f(\Delta, \Gamma, \Pi, \Lambda, \Omega, \Phi, \Psi, \Sigma, \Theta, \Xi)"), ("f(alpha(x), beta(x), chi(x), delta(x), ell(x), epsilon(x), eta(x))", r"f\!\left(\alpha(x), \beta(x), \chi(x), \delta(x), \ell(x), \varepsilon(x), \eta(x)\right)"), ("f(gamma(x), iota(x), kappa(x), lamda(x), mu(x), nu(x), omega(x), phi(x))", r"f\!\left(\gamma(x), \iota(x), \kappa(x), \lambda(x), \mu(x), \nu(x), \omega(x), \phi(x)\right)"), ("f(pi(x), rho(x), sigma(x), tau(x), theta(x), varphi(x), vartheta(x), xi(x), zeta(x))", r"f\!\left(\pi(x), \rho(x), \sigma(x), \tau(x), \theta(x), \varphi(x), \vartheta(x), \xi(x), \zeta(x)\right)"), ("f(Delta(x), GreekGamma(x), GreekPi(x), Lamda(x), Omega(x), Phi(x), Psi(x), Sigma(x), Theta(x), Xi(x))", r"f\!\left(\Delta(x), \Gamma(x), \Pi(x), \Lambda(x), \Omega(x), \Phi(x), \Psi(x), \Sigma(x), \Theta(x), \Xi(x)\right)"), ("f(alpha_(n), beta_(n), chi_(n), delta_(n), ell_(n), epsilon_(n), eta_(n))", r"f\!\left(\alpha_{n}, \beta_{n}, \chi_{n}, \delta_{n}, \ell_{n}, \varepsilon_{n}, \eta_{n}\right)"), ("f(gamma_(n), iota_(n), kappa_(n), lamda_(n), mu_(n), nu_(n), omega_(n), phi_(n))", r"f\!\left(\gamma_{n}, \iota_{n}, \kappa_{n}, \lambda_{n}, \mu_{n}, \nu_{n}, \omega_{n}, \phi_{n}\right)"), ("f(pi_(n), rho_(n), sigma_(n), tau_(n), theta_(n), varphi_(n), vartheta_(n), xi_(n), zeta_(n))", r"f\!\left(\pi_{n}, \rho_{n}, \sigma_{n}, \tau_{n}, \theta_{n}, \varphi_{n}, \vartheta_{n}, \xi_{n}, \zeta_{n}\right)"), ("f(Delta_(n), GreekGamma_(n), GreekPi_(n), Lamda_(n), Omega_(n), Phi_(n), Psi_(n), Sigma_(n), Theta_(n), Xi_(n))", r"f\!\left(\Delta_{n}, \Gamma_{n}, \Pi_{n}, \Lambda_{n}, \Omega_{n}, \Phi_{n}, \Psi_{n}, \Sigma_{n}, \Theta_{n}, \Xi_{n}\right)"), ("f(a)(b)", r"f(a)(b)"), ("Mul(f, g)(x)", r"\left(f g\right)(x)"), ("Add(f, g)(x)", r"\left(f + g\right)(x)"), ("c_(m, n, p)(x, y, z)", r"c_{m, n, p}(x, y, z)"), ("f_(Div(-3, 2))(Div(-3, 2))", r"f_{-3 / 2}\!\left(-\frac{3}{2}\right)"), ("Mul(2, Pi, NumberI)", r"2 \pi i"), ("Mul(-2, Pi, NumberI)", r"-2 \pi i"), ("Mul(1)", r"1"), ("Mul(-1)", r"-1"), ("Mul(1, x, y)", r" x y"), ("Mul(-1, x, y)", r"- x y"), ("Mul(1, 2, 3)", r"1 \cdot 2 \cdot 3"), ("Mul(-1, 2, 3)", r"-1 \cdot 2 \cdot 3"), ("Mul(-1, -1)", r"-1 \cdot \left(-1\right)"), ("Add(2, x)", r"2 + x"), ("Sub(2, x)", r"2 - x"), ("Add(2, Neg(x))", r"2 + \left(-x\right)"), ("Sub(2, Neg(x))", r"2 - \left(-x\right)"), ("Add(2, Sub(x, y))", r"2 + \left(x - y\right)"), ("Sub(2, Add(x, y))", r"2 - \left(x + y\right)"), ("Sub(2, Sub(x, y))", r"2 - \left(x - y\right)"), ("Add(-3, -4, -5)", r"-3-4-5"), ("Add(-3, Mul(-4, x), -5)", r"-3-4 x-5"), ("Add(-3, Mul(-4, x), Pos(5))", r"-3-4 x+5"), ("Add(-3, Div(Mul(-4, x), 7), -5)", r"-3-\frac{4 x}{7}-5"), ("Add(-3, Div(Mul(4, x), 7), -5)", r"-3 + \frac{4 x}{7}-5"), ("Mul(0, 1)", r"0 \cdot 1"), ("Mul(3, Pow(2, n))", r"3 \cdot {2}^{n}"), ("Mul(3, Pow(-1, n))", r"3 \cdot {\left(-1\right)}^{n}"), ("Mul(-3, Pow(-1, n))", r"-3 \cdot {\left(-1\right)}^{n}"), ("Mul(-1, -2, -3)", r"-1 \cdot \left(-2\right) \cdot \left(-3\right)"), ("Div(-1, 3)", r"-\frac{1}{3}"), ("Div(Mul(-5, Pi), 3)", r"-\frac{5 \pi}{3}"), ("Div(Neg(Mul(5, Pi)), 3)", r"-\frac{5 \pi}{3}"), ("Div(Add(Add(Mul(-5, Pow(x, 2)), Mul(4, x)), 1), Add(Mul(3, x), y))", r"\frac{-5 {x}^{2} + 4 x + 1}{3 x + y}"), ("Pow(2, n)", r"{2}^{n}"), ("Pow(-1, n)", r"{\left(-1\right)}^{n}"), ("Pow(10, Pow(10, -10))", r"{10}^{{10}^{-10}}"), ("Pow(2, Div(-1, 3))", r"{2}^{-1 / 3}"), ("Pow(2, Div(-1, Mul(3, n)))", r"{2}^{-1 / \left(3 n\right)}"), ("Equal(Add(Pow(Sin(x), 2), Pow(Cos(x), 2)), 1)", r"\sin^{2}\!\left(x\right) + \cos^{2}\!\left(x\right) = 1"), ("Set(Set(), Set(1), Set(1, 2, 3))", r"\left\{\left\{\right\}, \left\{1\right\}, \left\{1, 2, 3\right\}\right\}"), ("Tuple(Tuple(), Tuple(1), Tuple(1, 2, 3))", r"\left(\left(\right), \left(1\right), \left(1, 2, 3\right)\right)"), ("List(List(), List(1), List(1, 2, 3))", r"\left[\left[\right], \left[1\right], \left[1, 2, 3\right]\right]"), ("Set(f(x), For(x, CC))", r"\left\{ f(x) : x \in \mathbb{C} \right\}"), ("Set(f(x), For(x, CC), NotEqual(x, 0))", r"\left\{ f(x) : x \in \mathbb{C}\,\mathbin{\operatorname{and}}\, x \ne 0 \right\}"), ("List(Floor(x), Ceil(x), Abs(x), RealAbs(x), Conjugate(z), Sqrt(x))", r"\left[\left\lfloor x \right\rfloor, \left\lceil x\right\rceil, \left|x\right|, \left|x\right|, \overline{z}, \sqrt{x}\right]"), ("List(Floor(Div(1, 2)), Ceil(Div(1, 2)), Abs(Div(1, 2)), RealAbs(Div(1, 2)), Conjugate(Div(1, 2)), Sqrt(Div(1, 2)))", r"\left[\left\lfloor \frac{1}{2} \right\rfloor, \left\lceil \frac{1}{2}\right\rceil, \left|\frac{1}{2}\right|, \left|\frac{1}{2}\right|, \overline{\frac{1}{2}}, \sqrt{\frac{1}{2}}\right]"), ("And(Equal(Length(Tuple(1, 2, 3)), 3), Equal(Cardinality(Set()), 0))", r"\# \left(1, 2, 3\right) = 3 \;\mathbin{\operatorname{and}}\; \# \left\{\right\} = 0"), ("Tuple(Parentheses(x), Brackets(x), Braces(x), AngleBrackets(x))", r"\left(\left(x\right), \left[x\right], \left\{x\right\}, \left\langle x\right\rangle\right)"), ("Tuple(Parentheses(Div(1, 2)), Brackets(Div(1, 2)), Braces(Div(1, 2)), AngleBrackets(Div(1, 2)))", r"\left(\left(\frac{1}{2}\right), \left[\frac{1}{2}\right], \left\{\frac{1}{2}\right\}, \left\langle \frac{1}{2}\right\rangle\right)"), ("Concatenation(A, B)", r"A \,^\frown B"), ("Equal(Concatenation(Tuple(a, b), Tuple(c, d, e), Tuple()), Tuple(a, b, c, d, e))", r"\left(a, b\right) \,^\frown \left(c, d, e\right) \,^\frown \left(\right) = \left(a, b, c, d, e\right)"), ("Equal(f(x), Cases(Case(y, P(x)), Case(Neg(y), Q(x))))", r"f(x) = \begin{cases} y, & P(x)\\-y, & Q(x)\\ \end{cases}"), ("Equal(f(x), Cases(Case(y, P(x)), Case(Neg(y), Q(x)), Case(0, Otherwise)))", r"f(x) = \begin{cases} y, & P(x)\\-y, & Q(x)\\0, & \text{otherwise}\\ \end{cases}"), ("And(Equal(True, Not(False)), Equal(False, Not(True)))", r"\operatorname{True} = \operatorname{not} \operatorname{False} \;\mathbin{\operatorname{and}}\; \operatorname{False} = \operatorname{not} \operatorname{True}"), ("All(Greater(x, 0), For(x, S))", r"x > 0 \;\text{ for all } x \in S"), ("All(Greater(x, 0), For(x, S), P(x))", r"x > 0 \;\text{ for all } x \in S \text{ with } P(x)"), ("Exists(Greater(x, 0), For(x, S))", r"x > 0 \;\text{ for some } x \in S"), ("Exists(Greater(x, 0), For(x, S), P(x))", r"x > 0 \;\text{ for some } x \in S \text{ with } P(x)"), ("Logic(All(Greater(x, 0), For(x, S)))", r"\forall x \in S : \, x > 0"), ("Logic(All(Greater(x, 0), For(x, S), P(x)))", r"\forall x \in S, \,P(x) : \, x > 0"), ("Logic(Exists(Greater(x, 0), For(x, S)))", r"\exists x \in S : \, x > 0"), ("Logic(Exists(Greater(x, 0), For(x, S), P(x)))", r"\exists x \in S, \,P(x) : \, x > 0"), ("Or(Q, And(P, Q, Not(P), Or(Q, P), Not(Or(Q, P))))", r"Q \;\mathbin{\operatorname{or}}\; \left(P \;\mathbin{\operatorname{and}}\; Q \;\mathbin{\operatorname{and}}\; \operatorname{not} P \;\mathbin{\operatorname{and}}\; \left(Q \;\mathbin{\operatorname{or}}\; P\right) \;\mathbin{\operatorname{and}}\; \operatorname{not} \,\left(Q \;\mathbin{\operatorname{or}}\; P\right)\right)"), ("Logic(Or(Q, And(P, Q, Not(P), Or(Q, P), Not(Or(Q, P)))))", r"Q \,\lor\, \left(P \,\land\, Q \,\land\, \neg P \,\land\, \left(Q \,\lor\, P\right) \,\land\, \neg \left(Q \,\lor\, P\right)\right)"), ("Equivalent(A, B)", r"A \iff B"), ("Equivalent(Not(Equal(x, y)), NotEqual(x, y))", r"\left(\operatorname{not} \,\left(x = y\right)\right) \iff \left(x \ne y\right)"), ("Implies(P, And(R, S))", r"P \;\implies\; \left(R \;\mathbin{\operatorname{and}}\; S\right)"), ("Implies(Element(x, QQ), Element(x, RR))", r"x \in \mathbb{Q} \;\implies\; x \in \mathbb{R}"), ("And(Less(x, y), Less(x, y, z), LessEqual(x, y), LessEqual(x, y, z))", r"x < y \;\mathbin{\operatorname{and}}\; x < y < z \;\mathbin{\operatorname{and}}\; x \le y \;\mathbin{\operatorname{and}}\; x \le y \le z"), ("And(Greater(x, y), Greater(x, y, z), GreaterEqual(x, y), GreaterEqual(x, y, z))", r"x > y \;\mathbin{\operatorname{and}}\; x > y > z \;\mathbin{\operatorname{and}}\; x \ge y \;\mathbin{\operatorname{and}}\; x \ge y \ge z"), ("Subset(Primes, NN, ZZ, QQ, RR, CC)", r"\mathbb{P} \subset \mathbb{N} \subset \mathbb{Z} \subset \mathbb{Q} \subset \mathbb{R} \subset \mathbb{C}"), ("Subset(QQ, AlgebraicNumbers, CC)", r"\mathbb{Q} \subset \overline{\mathbb{Q}} \subset \mathbb{C}"), ("SubsetEqual(S, QQ)", r"S \subseteq \mathbb{Q}"), ("NotElement(123456789012345678901234567890, SetMinus(QQ, ZZ))", r"123456789012345678901234567890 \notin \mathbb{Q} \setminus \mathbb{Z}"), ("KroneckerDelta(x, Div(1, 2))", r"\delta_{(x,1 / 2)}"), ("Set(Interval(a, b), OpenInterval(a, b), ClosedOpenInterval(a, b), OpenClosedInterval(a, b))", r"\left\{\left[a, b\right], \left(a, b\right), \left[a, b\right), \left(a, b\right]\right\}"), ("Set(Interval(a, Div(1, 2)), OpenInterval(a, Div(1, 2)), ClosedOpenInterval(a, Div(1, 2)), OpenClosedInterval(a, Div(1, 2)))", r"\left\{\left[a, 1 / 2\right], \left(a, 1 / 2\right), \left[a, 1 / 2\right), \left(a, 1 / 2\right]\right\}"), ("Set(RealBall(m, r), OpenRealBall(m, r))", r"\left\{\left[m \pm r\right], \left(m \pm r\right)\right\}"), ("Set(ClosedComplexDisk(m, r), OpenComplexDisk(m, r))", r"\left\{\overline{D}(m, r), D(m, r)\right\}"), ("Set(Undefined, UnsignedInfinity, Pos(Infinity), Neg(Infinity))", r"\left\{\mathfrak{u}, \hat{\infty}, +\infty, -\infty\right\}"), ("Equal(RealSignedInfinities, Set(Pos(Infinity), Neg(Infinity)))", r"\{\pm \infty\} = \left\{+\infty, -\infty\right\}"), ("Equal(ComplexSignedInfinities, Set(Mul(Exp(Mul(NumberI, theta)), Infinity), For(theta, OpenClosedInterval(Neg(Pi), Pi))))", r"\{[e^{i \theta}] \infty\} = \left\{ e^{i \theta} \cdot \infty : \theta \in \left(-\pi, \pi\right] \right\}"), ("Equal(RealInfinities, Union(RealSignedInfinities, Set(UnsignedInfinity)))", r"\{\hat{\infty}, \pm \infty\} = \{\pm \infty\} \cup \left\{\hat{\infty}\right\}"), ("Equal(ComplexInfinities, Union(ComplexSignedInfinities, Set(UnsignedInfinity)))", r"\{\hat{\infty}, [e^{i \theta}] \infty\} = \{[e^{i \theta}] \infty\} \cup \left\{\hat{\infty}\right\}"), ("Equal(ExtendedRealNumbers, Union(RR, RealSignedInfinities))", r"\overline{\mathbb{R}} = \mathbb{R} \cup \{\pm \infty\}"), ("Equal(SignExtendedComplexNumbers, Union(CC, ComplexSignedInfinities))", r"\overline{\mathbb{C}}_{[e^{i \theta}] \infty} = \mathbb{C} \cup \{[e^{i \theta}] \infty\}"), ("Equal(ProjectiveRealNumbers, Union(RR, Set(UnsignedInfinity)))", r"\hat{\mathbb{R}}_{\infty} = \mathbb{R} \cup \left\{\hat{\infty}\right\}"), ("Equal(ProjectiveComplexNumbers, Union(CC, Set(UnsignedInfinity)))", r"\hat{\mathbb{C}}_{\infty} = \mathbb{C} \cup \left\{\hat{\infty}\right\}"), ("Equal(RealSingularityClosure, Union(RR, Set(UnsignedInfinity), RealSignedInfinities, Set(Undefined)))", r"\overline{\mathbb{R}}_{\text{Sing}} = \mathbb{R} \cup \left\{\hat{\infty}\right\} \cup \{\pm \infty\} \cup \left\{\mathfrak{u}\right\}"), ("Equal(ComplexSingularityClosure, Union(CC, Set(UnsignedInfinity), ComplexSignedInfinities, Set(Undefined)))", r"\overline{\mathbb{C}}_{\text{Sing}} = \mathbb{C} \cup \left\{\hat{\infty}\right\} \cup \{[e^{i \theta}] \infty\} \cup \left\{\mathfrak{u}\right\}"), ("Set(Mul(Infinity, Infinity), Mul(Mul(a, b), Infinity), Mul(NumberI, Infinity), Mul(Infinity, NumberI))", r"\left\{\infty \cdot \infty, a b \cdot \infty, i \cdot \infty, \infty i\right\}"), ("ArgMin(Add(f(x), g(x)), For(x, RR), NotEqual(x, 0))", r"\mathop{\operatorname{arg\,min}\,}\limits_{x \in \mathbb{R},\,x \ne 0} \left[f(x) + g(x)\right]"), ("List(ArgMin(f(x), For(x, S)), ArgMax(f(x), For(x, S)), ArgMin(f(x), For(x, S), P(x)), ArgMax(f(x), For(x, S), P(x)))", r"\left[\mathop{\operatorname{arg\,min}\,}\limits_{x \in S} f(x), \mathop{\operatorname{arg\,max}\,}\limits_{x \in S} f(x), \mathop{\operatorname{arg\,min}\,}\limits_{x \in S,\,P(x)} f(x), \mathop{\operatorname{arg\,max}\,}\limits_{x \in S,\,P(x)} f(x)\right]"), ("List(Minimum(f(x), For(x, S)), Maximum(f(x), For(x, S)), Minimum(f(x), For(x, S), P(x)), Maximum(f(x), For(x, S), P(x)))", r"\left[\mathop{\min\,}\limits_{x \in S} f(x), \mathop{\max\,}\limits_{x \in S} f(x), \mathop{\min\,}\limits_{x \in S,\,P(x)} f(x), \mathop{\max\,}\limits_{x \in S,\,P(x)} f(x)\right]"), ("List(ArgMinUnique(f(x), For(x, S)), ArgMaxUnique(f(x), For(x, S)), ArgMinUnique(f(x), For(x, S), P(x)), ArgMaxUnique(f(x), For(x, S), P(x)))", r"\left[\mathop{\operatorname{arg\,min*}\,}\limits_{x \in S} f(x), \mathop{\operatorname{arg\,max*}\,}\limits_{x \in S} f(x), \mathop{\operatorname{arg\,min*}\,}\limits_{x \in S,\,P(x)} f(x), \mathop{\operatorname{arg\,max*}\,}\limits_{x \in S,\,P(x)} f(x)\right]"), ("List(Infimum(f(x), For(x, S)), Supremum(f(x), For(x, S)), Infimum(f(x), For(x, S), P(x)), Supremum(f(x), For(x, S), P(x)))", r"\left[\mathop{\operatorname{inf}\,}\limits_{x \in S} f(x), \mathop{\operatorname{sup}\,}\limits_{x \in S} f(x), \mathop{\operatorname{inf}\,}\limits_{x \in S,\,P(x)} f(x), \mathop{\operatorname{sup}\,}\limits_{x \in S,\,P(x)} f(x)\right]"), ("List(Solutions(Q(x), For(x, S)), Zeros(f(x), For(x, S)), Solutions(Q(x), For(x, S), P(x)), Zeros(f(x), For(x, S), P(x)))", r"\left[\mathop{\operatorname{solutions}\,}\limits_{x \in S} Q(x), \mathop{\operatorname{zeros}\,}\limits_{x \in S} f(x), \mathop{\operatorname{solutions}\,}\limits_{x \in S,\,P(x)} Q(x), \mathop{\operatorname{zeros}\,}\limits_{x \in S,\,P(x)} f(x)\right]"), ("List(UniqueSolution(Q(x), For(x, S)), UniqueZero(f(x), For(x, S)), UniqueSolution(Q(x), For(x, S), P(x)), UniqueZero(f(x), For(x, S), P(x)))", r"\left[\mathop{\operatorname{solution*}\,}\limits_{x \in S} Q(x), \mathop{\operatorname{zero*}\,}\limits_{x \in S} f(x), \mathop{\operatorname{solution*}\,}\limits_{x \in S,\,P(x)} Q(x), \mathop{\operatorname{zero*}\,}\limits_{x \in S,\,P(x)} f(x)\right]"), ("Sum(f(n) + g(n), For(n, a, b))", r"\sum_{n=a}^{b} \left(f(n) + g(n)\right)"), ("Sum(f(n), For(n, ZZ))", r"\sum_{n \in \mathbb{Z}} f(n)"), ("Sum(f(n), For(n, ZZ), NotEqual(n, 0))", r"\sum_{\textstyle{n \in \mathbb{Z} \atop n \ne 0}} f(n)"), ("Sum(f(n), For(n, a, b), NotEqual(n, 0))", r"\sum_{\textstyle{n=a \atop n \ne 0}}^{b} f(n)"), ("Sum(f(n), For(n, a, b))", r"\sum_{n=a}^{b} f(n)"), ("Product(f(n) + g(n), For(n, a, b))", r"\prod_{n=a}^{b} \left(f(n) + g(n)\right)"), ("Product(f(n), For(n, NN))", r"\prod_{n \in \mathbb{N}} f(n)"), ("Product(f(n), For(n, NN), NotEqual(g(n), 0))", r"\prod_{\textstyle{n \in \mathbb{N} \atop g(n) \ne 0}} f(n)"), ("Product(f(n), For(n, a, b), NotEqual(n, 0))", r"\prod_{\textstyle{n=a \atop n \ne 0}}^{b} f(n)"), ("Product(f(n), For(n, a, b))", r"\prod_{n=a}^{b} f(n)"), ("Equal(Set(f(n), For(n, ZZ)), Union(Set(f(n), For(n, ZZ), IsEven(n)), Set(f(n), For(n, ZZ), IsOdd(n))))", r"\left\{ f(n) : n \in \mathbb{Z} \right\} = \left\{ f(n) : n \in \mathbb{Z}\,\mathbin{\operatorname{and}}\, n \text{ even} \right\} \cup \left\{ f(n) : n \in \mathbb{Z}\,\mathbin{\operatorname{and}}\, n \text{ odd} \right\}"), ("Equal(Primes, Set(p, For(p, NN), IsPrime(p)))", r"\mathbb{P} = \left\{ p : p \in \mathbb{N}\,\mathbin{\operatorname{and}}\, p \text{ prime} \right\}"), ("Equal(Sum(f(n), Element(n, ZZ)), Add(Sum(f(n), Element(n, ZZ), IsOdd(n)), Sum(f(n), Element(n, ZZ), IsEven(n))))", r"\sum_{n \in \mathbb{Z}} f(n) = \sum_{\textstyle{n \in \mathbb{Z} \atop n \text{ odd}}} f(n) + \sum_{\textstyle{n \in \mathbb{Z} \atop n \text{ even}}} f(n)"), ("Set(DivisorSum(f(d), For(d, n)), DivisorSum(f(d), For(d, n), IsOdd(d)), DivisorSum(Add(f(d), g(d)), For(d, n)))", r"\left\{\sum_{d \mid n} f(d), \sum_{d \mid n,\, d \text{ odd}} f(d), \sum_{d \mid n} \left(f(d) + g(d)\right)\right\}"), ("Set(DivisorProduct(f(d), For(d, n)), DivisorProduct(f(d), For(d, n), IsOdd(d)), DivisorProduct(Add(f(d), g(d)), For(d, n)))", r"\left\{\prod_{d \mid n} f(d), \prod_{d \mid n,\, d \text{ odd}} f(d), \prod_{d \mid n} \left(f(d) + g(d)\right)\right\}"), ("Set(PrimeSum(f(p), For(p)), PrimeSum(f(p), For(p), NotElement(p, S)), PrimeProduct(f(p), For(p)), PrimeProduct(f(p), For(p), NotElement(p, S)))", r"\left\{\sum_{p} f(p), \sum_{p \notin S} f(p), \prod_{p} f(p), \prod_{p \notin S} f(p)\right\}"), ("Integral(f(x), For(x, -Infinity, Infinity))", r"\int_{-\infty}^{\infty} f(x) \, dx"), ("Integral(f(x), For(x, RR))", r"\int_{x \in \mathbb{R}} f(x) \, dx"), ("Integral(f(x) + g(x) / h(x), For(x, a, b))", r"\int_{a}^{b} \left(f(x) + \frac{g(x)}{h(x)}\right) \, dx"), ("Set(Derivative(f(x_), For(x_, x)), Derivative(f(x_), For(x_, Div(x, y))), Derivative(Gamma(x_), For(x_, 1)))", r"\left\{f'\!\left(x\right), f'\!\left(\frac{x}{y}\right), \Gamma'\!\left(1\right)\right\}"), ("Set(Derivative(f(x_), For(x_, x, 0)), Derivative(f(x_), For(x_, x, 1)), Derivative(f(x_), For(x_, x, 2)), Derivative(f(x_), For(x_, x, 3)), Derivative(f(x_), For(x_, x, 4)), Derivative(f(x_), For(x_, x, n)), Derivative(f(x_), For(x_, x, Add(Mul(2, n), 3))))", r"\left\{{f}^{(0)}\!\left(x\right), f'\!\left(x\right), f''\!\left(x\right), f'''\!\left(x\right), {f}^{(4)}\!\left(x\right), {f}^{(n)}\!\left(x\right), {f}^{(2 n + 3)}\!\left(x\right)\right\}"), ("Set(Derivative(f(Add(x, 1)), For(x, x)), Derivative(f(Add(x, 1)), For(x, x, 0)), Derivative(f(Add(x, 1)), For(x, x, 1)), Derivative(f(Add(x, 1)), For(x, x, n)))", r"\left\{\frac{d}{d x}\, f\!\left(x + 1\right), \frac{d^{0}}{{d x}^{0}}\, f\!\left(x + 1\right), \frac{d}{d x}\, f\!\left(x + 1\right), \frac{d^{n}}{{d x}^{n}}\, f\!\left(x + 1\right)\right\}"), ("Set(Derivative(Add(f(x), g(x)), For(x, Add(y, 3))), Derivative(Add(f(x), g(x)), For(x, Add(y, 3), 5)))", r"\left\{\left[\frac{d}{d x}\, \left[f(x) + g(x)\right] \right]_{x = y + 3}, \left[\frac{d^{5}}{{d x}^{5}}\, \left[f(x) + g(x)\right] \right]_{x = y + 3}\right\}"), ("Set(RealDerivative(f(x), For(x, 1)), ComplexDerivative(f(x), For(x, 1)), ComplexBranchDerivative(f(x), For(x, 1)), MeromorphicDerivative(f(x), For(x, 1)))", r"\left\{f'\!\left(1\right), f'\!\left(1\right), f'\!\left(1\right), f'\!\left(1\right)\right\}"), ("Set(Limit(f(x), For(x, a)), Limit(f(x), For(x, a), P(x)))", r"\left\{\lim_{x \to a} f(x), \lim_{x \to a,\,P(x)} f(x)\right\}"), ("Set(Limit(f(x), For(x, a)), RealLimit(f(x), For(x, a)), ComplexLimit(f(x), For(x, a)), MeromorphicLimit(f(x), For(x, a)))", r"\left\{\lim_{x \to a} f(x), \lim_{x \to a} f(x), \lim_{x \to a} f(x), \lim_{x \to a} f(x)\right\}"), ("Set(LeftLimit(f(x), For(x, 0)), RightLimit(f(x), For(x, 0)))", r"\left\{\lim_{x \to {0}^{-}} f(x), \lim_{x \to {0}^{+}} f(x)\right\}"), ("Set(SequenceLimit(f(n), For(n, Infinity)), SequenceLimitInferior(f(n), For(n, Infinity)), SequenceLimitSuperior(f(n), For(n, Infinity)))", r"\left\{\lim_{n \to \infty} f(n), \liminf_{n \to \infty} f(n), \limsup_{n \to \infty} f(n)\right\}"), ("Sub(Limit(Add(f(x), g(x)), For(x, a)), Limit(Sub(f(x), g(x)), For(x, a)))", r"\lim_{x \to a} \left[f(x) + g(x)\right] - \lim_{x \to a} \left[f(x) - g(x)\right]"), ("Divides(GCD(a, b), LCM(a, b))", r"\gcd(a, b) \mid \operatorname{lcm}(a, b)"), ("Set(Exp(x), Exp(Div(3, 2)), Exp(Add(Neg(Pow(x, 2)), x)), Exp(Abs(Im(z))), Exp(Div(3, Add(2, x))), Exp(Sin(x)))", r"\left\{e^{x}, e^{3 / 2}, e^{-{x}^{2} + x}, e^{\left|\operatorname{Im}(z)\right|}, \exp\!\left(\frac{3}{2 + x}\right), \exp\!\left(\sin(x)\right)\right\}"), ("Add(Sin(x), Cos(x), Tan(x), Cot(x), Sec(x), Csc(x))", r"\sin(x) + \cos(x) + \tan(x) + \cot(x) + \sec(x) + \csc(x)"), ("Add(Sinh(x), Cosh(x), Tanh(x), Coth(x), Sech(x), Csch(x))", r"\sinh(x) + \cosh(x) + \tanh(x) + \coth(x) + \operatorname{sech}(x) + \operatorname{csch}(x)"), ("Add(Asin(x), Acos(x), Atan(x), Acot(x), Asec(x), Acsc(x))", r"\operatorname{asin}(x) + \operatorname{acos}(x) + \operatorname{atan}(x) + \operatorname{acot}(x) + \operatorname{asec}(x) + \operatorname{acsc}(x)"), ("Add(Asinh(x), Acosh(x), Atanh(x), Acoth(x), Asech(x), Acsch(x))", r"\operatorname{asinh}(x) + \operatorname{acosh}(x) + \operatorname{atanh}(x) + \operatorname{acoth}(x) + \operatorname{asech}(x) + \operatorname{acsch}(x)"), ("Exp(Neg(Euler))", r"e^{-\gamma}"), ("Set(Re(z), Im(z), Atan2(y, x))", r"\left\{\operatorname{Re}(z), \operatorname{Im}(z), \operatorname{atan2}(y, x)\right\}"), ("Add(NumberE, GoldenRatio, CatalanConstant)", r"e + \varphi + G"), ("Add(Sinc(x), Pow(Sinc(x), 2))", r"\operatorname{sinc}(x) + \operatorname{sinc}^{2}\!\left(x\right)"), ("AGM(a, b)", r"\operatorname{agm}(a, b)"), ("And(Equal(LogBarnesG(z), Log(BarnesG(z))), Equal(LogGamma(z), Log(Gamma(z))))", r"\log G(z) = \log\!\left(G(z)\right) \;\mathbin{\operatorname{and}}\; \log \Gamma(z) = \log\!\left(\Gamma(z)\right)"), ("DirichletL(s, chi)", r"L(s, \chi)"), ("DirichletLambda(s, chi)", r"\Lambda(s, \chi)"), ("Implies(GeneralizedRiemannHypothesis, RiemannHypothesis)", r"\operatorname{GRH} \;\implies\; \operatorname{RH}"), ("Set(ModularJ(tau), ModularLambda(tau), JacobiTheta(n, z, tau))", r"\left\{j(\tau), \lambda(\tau), \theta_{n}\!\left(z, \tau\right)\right\}"), ("Set(WeierstrassP(z, tau), WeierstrassSigma(z, tau), WeierstrassZeta(z, tau))", r"\left\{\wp(z, \tau), \sigma(z, \tau), \zeta(z, \tau)\right\}"), ("Mul(ChebyshevT(n, x), ChebyshevU(n, x))", r"T_{n}\!\left(x\right) U_{n}\!\left(x\right)"), ("Add(FresnelC(z), FresnelS(z))", r"C(z) + S(z)"), ("Div(EisensteinE(Mul(2, n), tau), EisensteinG(Mul(2, n), tau))", r"\frac{E_{2 n}\!\left(\tau\right)}{G_{2 n}\!\left(\tau\right)}"), ("Equal(Div(IncompleteBeta(z, a, b), IncompleteBetaRegularized(z, a, b)), BetaFunction(a, b))", r"\frac{\mathrm{B}_{z}\!\left(a, b\right)}{I_{z}\!\left(a, b\right)} = \mathrm{B}(a, b)"), ("Set(PolyLog(s, z), HurwitzZeta(s, z), LerchPhi(z, s, a))", r"\left\{\operatorname{Li}_{s}\!\left(z\right), \zeta(s, z), \Phi(z, s, a)\right\}"), ("Equal(PartitionsP(n), Mul(Div(1, n), Sum(Mul(DivisorSigma(1, Sub(n, k)), PartitionsP(k)), For(k, 0, Sub(n, 1)))))", r"p(n) = \frac{1}{n} \sum_{k=0}^{n - 1} \sigma_{1}\!\left(n - k\right) p(k)"), ("MultiZetaValue(a, b, c)", r"\zeta(a, b, c)"), ("RiemannXi(s)", r"\xi(s)"), ("Mul(LiouvilleLambda(n), EulerPhi(n), MoebiusMu(n))", r"\lambda(n) \varphi(n) \mu(n)"), ("BetaFunction(a, b)", r"\mathrm{B}(a, b)"), ("PrimePi(x)", r"\pi(x)"), ("Equal(Min(a, b), Neg(Max(Neg(a), Neg(b))))", r"\min(a, b) = -\max\!\left(-a, -b\right)"), ("Equal(Arg(z), Div(Pi, 2))", r"\arg(z) = \frac{\pi}{2}"), ("NotEqual(Csgn(z), Sign(z))", r"\operatorname{csgn}(z) \ne \operatorname{sgn}(z)"), ("Add(Factorial(0), Factorial(1), Div(1, Factorial(-3)), Factorial(Div(1, 2)), Factorial(Factorial(n)), DoubleFactorial(n))", r"0! + 1! + \frac{1}{\left(-3\right)!} + \left(\frac{1}{2}\right)! + \left(n!\right)! + n!!"), ("List(Binomial(x, n), RisingFactorial(x, n), FallingFactorial(x, n), StirlingCycle(x, n), StirlingS1(x, n), StirlingS2(x, n))", r"\left[{x \choose n}, \left(x\right)_{n}, \left(x\right)^{\underline{n}}, \left[{x \atop n}\right], s\!\left(x, n\right), \left\{{x \atop n}\right\}\right]"), ("Add(BellNumber(5), BernoulliB(5), EulerE(5), Fibonacci(5), HarmonicNumber(5), Prime(5), RiemannZetaZero(5))", r"\operatorname{B}_{5} + B_{5} + E_{5} + F_{5} + H_{5} + p_{5} + \rho_{5}"), ("List(LegendreSymbol(p, q), JacobiSymbol(p, q), KroneckerSymbol(p, q))", r"\left[\left(\frac{p}{q}\right), \left(\frac{p}{q}\right), \left(\frac{p}{q}\right)\right]"), ("Add(ExpIntegralEi(x), ExpIntegralE(n, x), SinIntegral(x), SinhIntegral(x), CosIntegral(x), CoshIntegral(x), LogIntegral(x))", r"\operatorname{Ei}(x) + E_{n}\!\left(x\right) + \operatorname{Si}(x) + \operatorname{Shi}(x) + \operatorname{Ci}(x) + \operatorname{Chi}(x) + \operatorname{li}(x)"), ("Mul(BesselJ(nu, z), BesselI(nu, z), BesselY(nu, z), BesselK(nu, z))", r"J_{\nu}\!\left(z\right) I_{\nu}\!\left(z\right) Y_{\nu}\!\left(z\right) K_{\nu}\!\left(z\right)"), ("Equal(AiryAi(AiryAiZero(n)), AiryBi(AiryBiZero(n)), 0)", r"\operatorname{Ai}\!\left(a_{n}\right) = \operatorname{Bi}\!\left(b_{n}\right) = 0"), ("Equal(BesselJ(nu, BesselJZero(nu, n)), BesselY(nu, BesselYZero(nu, n)), 0)", r"J_{\nu}\!\left(j_{\nu, n}\right) = Y_{\nu}\!\left(y_{\nu, n}\right) = 0"), ("Equal(RiemannZeta(s), Mul(Mul(Mul(Mul(2, Pow(Mul(2, Pi), Sub(s, 1))), Sin(Div(Mul(Pi, s), 2))), Gamma(Sub(1, s))), RiemannZeta(Sub(1, s))))", r"\zeta(s) = 2 {\left(2 \pi\right)}^{s - 1} \sin\!\left(\frac{\pi s}{2}\right) \Gamma\!\left(1 - s\right) \zeta\!\left(1 - s\right)"), ("Pow(Div(Pow(DedekindEta(Mul(2, tau)), 2), Mul(DedekindEta(tau), DedekindEta(Mul(4, tau)))), 24)", r"{\left(\frac{\eta^{2}\!\left(2 \tau\right)}{\eta(\tau) \eta\!\left(4 \tau\right)}\right)}^{24}"), ("Mul(Mul(Erf(z), Erfc(z)), Erfi(z))", r"\operatorname{erf}(z) \operatorname{erfc}(z) \operatorname{erfi}(z)"), ("Mul(EllipticK(m), EllipticE(m), EllipticPi(n, m))", r"K(m) E(m) \Pi(n, m)"), ("Mul(IncompleteEllipticE(z, m), IncompleteEllipticF(z, m), IncompleteEllipticPi(n, z, m))", r"E(z, m) F(z, m) \Pi(n, z, m)"), ("Add(CarlsonRF(x, y, z), CarlsonRG(x, y, z), CarlsonRJ(x, y, z, w), CarlsonRD(x, y, z), CarlsonRC(x, y))", r"R_F(x, y, z) + R_G(x, y, z) + R_J(x, y, z, w) + R_D(x, y, z) + R_C(x, y)"), ("Mul(Hypergeometric0F1(b, z), Hypergeometric0F1Regularized(b, z))", r"\,{}_0F_1(b, z) \,{}_0{\textbf F}_1(b, z)"), ("Mul(Hypergeometric1F1(a, b, z), Hypergeometric1F1Regularized(a, b, z))", r"\,{}_1F_1(a, b, z) \,{}_1{\textbf F}_1(a, b, z)"), ("Hypergeometric2F0(a, b, z)", r"\,{}_2F_0(a, b, z)"), ("Mul(HypergeometricU(a, b, z), HypergeometricUStar(a, b, z))", r"U(a, b, z) U^{*}(a, b, z)"), ("Mul(Hypergeometric2F1(a, b, c, z), Hypergeometric2F1Regularized(a, b, c, z))", r"\,{}_2F_1(a, b, c, z) \,{}_2{\textbf F}_1(a, b, c, z)"), ("Mul(Hypergeometric1F2(a, b, c, z), Hypergeometric1F2Regularized(a, b, c, z))", r"\,{}_1F_2(a, b, c, z) \,{}_1{\textbf F}_2(a, b, c, z)"), ("Mul(Hypergeometric2F2(a, b, c, d, z), Hypergeometric2F2Regularized(a, b, c, d, z))", r"\,{}_2F_2(a, b, c, d, z) \,{}_2{\textbf F}_2(a, b, c, d, z)"), ("Mul(Hypergeometric3F2(a, b, c, d, e, z), Hypergeometric3F2Regularized(a, b, c, d, e, z))", r"\,{}_3F_2(a, b, c, d, e, z) \,{}_3{\textbf F}_2(a, b, c, d, e, z)"), ("(Hypergeometric2F1Regularized(Div(-1,4),Div(1,4),1/2, (x-1)/2)**2)", r"{\left(\,{}_2{\textbf F}_1\!\left(-\frac{1}{4}, \frac{1}{4}, \frac{1}{2}, \frac{x - 1}{2}\right)\right)}^{2}"), ("Matrix(List(List(a, b, c), List(d, e, f), List(g, h, 0)))", r"\displaystyle{\begin{pmatrix}a & b & c \\d & e & f \\g & h & 0\end{pmatrix}}"), ("Matrix2x2(a, b, c, d)", r"\displaystyle{\begin{pmatrix}a & b \\ c & d\end{pmatrix}}"), ("Set(RowMatrix(), RowMatrix(a), RowMatrix(a, b), RowMatrix(a, b, c), RowMatrix(a, b, c, d))", r"\left\{\displaystyle{\begin{pmatrix}\end{pmatrix}}, \displaystyle{\begin{pmatrix}a\end{pmatrix}}, \displaystyle{\begin{pmatrix}a & b\end{pmatrix}}, \displaystyle{\begin{pmatrix}a & b & c\end{pmatrix}}, \displaystyle{\begin{pmatrix}a & b & c & d\end{pmatrix}}\right\}"), ("Set(ColumnMatrix(), ColumnMatrix(a), ColumnMatrix(a, b), ColumnMatrix(a, b, c), ColumnMatrix(a, b, c, d))", r"\left\{\displaystyle{\begin{pmatrix}\end{pmatrix}}, \displaystyle{\begin{pmatrix}a\end{pmatrix}}, \displaystyle{\begin{pmatrix}a \\ b\end{pmatrix}}, \displaystyle{\begin{pmatrix}a \\ b \\ c\end{pmatrix}}, \displaystyle{\begin{pmatrix}a \\ b \\ c \\ d\end{pmatrix}}\right\}"), ("Set(DiagonalMatrix(), DiagonalMatrix(a), DiagonalMatrix(a, b), DiagonalMatrix(a, b, c), DiagonalMatrix(a, b, c, d))", r"\left\{\displaystyle{\begin{pmatrix}\end{pmatrix}}, \displaystyle{\begin{pmatrix}a\end{pmatrix}}, \displaystyle{\begin{pmatrix}a & \\ & b\end{pmatrix}}, \displaystyle{\begin{pmatrix}a & & \\ & b & \\ & & c\end{pmatrix}}, \displaystyle{\begin{pmatrix}a & & & \\ & b & & \\ & & c & \\ & & & d\end{pmatrix}}\right\}"), ("Matrix(c_(m, n), For(m, 1, N), For(n, 1, 10))", r"\displaystyle{\begin{pmatrix} c_{1, 1} & c_{1, 2} & \cdots & c_{1, 10} \\ c_{2, 1} & c_{2, 2} & \cdots & c_{2, 10} \\ \vdots & \vdots & \ddots & \vdots \\ c_{N, 1} & c_{N, 2} & \cdots & c_{N, 10} \end{pmatrix}}"), ("Matrix(ShowExpandedNormalForm(Div(1, Sub(Add(m, n), 1))), For(m, 1, 10), For(n, 1, 10))", r"\displaystyle{\begin{pmatrix} 1 & \frac{1}{2} & \cdots & \frac{1}{10} \\ \frac{1}{2} & \frac{1}{3} & \cdots & \frac{1}{11} \\ \vdots & \vdots & \ddots & \vdots \\ \frac{1}{10} & \frac{1}{11} & \cdots & \frac{1}{19} \end{pmatrix}}"), ("Add(ZeroMatrix(2), IdentityMatrix(2), HilbertMatrix(2))", r"0_{2} + I_{2} + H_{2}"), ("Set(SpecialLinearGroup(n, ZZ), GeneralLinearGroup(n, ZZ))", r"\left\{\operatorname{SL}_{n}\!\left(\mathbb{Z}\right), \operatorname{GL}_{n}\!\left(\mathbb{Z}\right)\right\}"), ("Equal(One(QQ), 1)", r"1_{\mathbb{Q}} = 1"), ("Equal(Zero(QQ), 0)", r"0_{\mathbb{Q}} = 0"), ("List(Polynomials(QQ, x), Polynomials(QQ, x, y), Polynomials(QQ, Tuple()), Polynomials(QQ, Tuple(x)), Polynomials(QQ, Tuple(x, y)))", r"\left[\mathbb{Q}[x], \mathbb{Q}[x, y], \mathbb{Q}[], \mathbb{Q}[x], \mathbb{Q}[x, y]\right]"), ("List(Polynomials(QQ, x), PolynomialFractions(QQ, x), FormalPowerSeries(QQ, x), FormalLaurentSeries(QQ, x), FormalPuiseuxSeries(QQ, x))", r"\left[\mathbb{Q}[x], \mathbb{Q}(x), \mathbb{Q}[[x]], \mathbb{Q}(\!(x)\!), \mathbb{Q}\!\left\langle\!\left\langle x \right\rangle\!\right\rangle\right]"), ("Set(IntegersGreaterEqual(0), IntegersGreaterEqual(n), IntegersLessEqual(0), IntegersLessEqual(n))", r"\left\{\mathbb{Z}_{\ge 0}, \mathbb{Z}_{\ge n}, \{0, -1, \ldots\}, \mathbb{Z}_{\le n}\right\}"), ("List(Range(a, b), Range(1, b), Range(-3, 5))", r"\left[\{a, a + 1, \ldots, b\}, \{1, 2, \ldots, b\}, \{-3, -2, \ldots, 5\}\right]"), ("CongruentMod(f(n), 0, p)", r"f(n) \equiv 0 \pmod {p }"), ("PrimitiveReducedPositiveIntegralBinaryQuadraticForms(D)", r"\mathcal{Q}^{*}_{D}"), ("Set(EllipticRootE(1, tau), EllipticRootE(2, tau), EllipticRootE(3, tau))", r"\left\{e_{1}\!\left(\tau\right), e_{2}\!\left(\tau\right), e_{3}\!\left(\tau\right)\right\}"), ("GaussSum(n, chi)", r"G_{n}\!\left(\chi\right)"), ("Set(GlaisherConstant, KhinchinConstant)", r"\left\{A, K\right\}"), ('Decimal("0.3141")', r"0.3141"), ('Decimal("0.3141e-27")', r"0.3141 \cdot 10^{-27}"), ("Set(DigammaFunction(z), DigammaFunction(z, 1), DigammaFunction(z, n))", r"\left\{\psi(z), \psi'\!\left(z\right), {\psi}^{(n)}\!\left(z\right)\right\}"), ("Set(AiryAi(z, 1), AiryAi(z, 2), AiryBi(z, n), BesselJ(n, z, 1), BesselY(n, z, 2), BesselK(n, z, Add(Mul(3, r), 1)))", r"\left\{\operatorname{Ai}'\!\left(z\right), \operatorname{Ai}''\!\left(z\right), {\operatorname{Bi}}^{(n)}\!\left(z\right), J'_{n}\!\left(z\right), Y''_{n}\!\left(z\right), {K}^{(3 r + 1)}_{n}\!\left(z\right)\right\}"), ("Set(HankelH1(n, z), HankelH2(n, z))", r"\left\{H^{(1)}_{n}\!\left(z\right), H^{(2)}_{n}\!\left(z\right)\right\}"), ("Element(DirichletCharacter(q, k), PrimitiveDirichletCharacters(q))", r"\chi_{q \, . \, k} \in G^{\text{Primitive}}_{q}"), ("DirichletCharacter(q, k, n)", r"\chi_{q \, . \, k}(n)"), ("JacobiTheta(3, z, tau, 2)", r"\theta''_{3}\!\left(z, \tau\right)"), ("Set(RiemannZeta(s, 1), RiemannZeta(s, r))", r"\left\{\zeta'\!\left(s\right), {\zeta}^{(r)}\!\left(s\right)\right\}"), ("Subscript(x, y)", r"{x}_{y}"), ("Set(BernsteinEllipse(r), UnitCircle, PSL2Z, AGMSequence(n, a, b), CarlsonHypergeometricR, CarlsonHypergeometricT)", r"\left\{\mathcal{E}_{r}, \mathbb{T}, \operatorname{PSL}_2(\mathbb{Z}), \operatorname{agm}_{n}\!\left(a, b\right), R, T\right\}"), ("Mul(Mul(Pow(Fibonacci(n), 2), Pow(x_(a), 2)), Pow(alpha_(n), 2))", r"F_{n}^{2} x_{a}^{2} \alpha_{n}^{2}"), ("Set(Derivative(ChebyshevT(n, x_), For(x_, x)), Derivative(ChebyshevT(n, x_), For(x_, x, 2)), Derivative(ChebyshevT(n, x_), For(x_, x, 4)))", r"\left\{T'_{n}\!\left(x\right), T''_{n}\!\left(x\right), {T}^{(4)}_{n}\!\left(x\right)\right\}"), ("Poles(Gamma(z), For(z, CC))", r"\mathop{\operatorname{poles}\,}\limits_{z \in \mathbb{C}} \Gamma(z)"), ("Equal(Item(Tuple(a, b, c), 2), b)", r"{\left(a, b, c\right)}_{2} = b"), ("Set(Tuple(n, For(n, a, b)), List(Pow(Neg(n), 2), For(n, 1, 100)), Set(f_(n), For(n, 0, N)))", r"\left\{\left(a, a + 1, \ldots, b\right), \left[{\left(-1\right)}^{2}, {\left(-2\right)}^{2}, \ldots, {\left(-100\right)}^{2}\right], \left\{f_{0}, f_{1}, \ldots, f_{N}\right\}\right\}"), ("Set(Tuple(1, 0, Repeat(3, N)), Tuple(1, 0, Repeat(1, 2, 3, N)))", r"\left\{\left(1, 0, \underbrace{3, \ldots, 3}_{N \text{ times}}\right), \left(1, 0, \underbrace{1, 2, 3, \ldots, 1, 2, 3}_{\left(1, 2, 3\right) \; N \text{ times}}\right)\right\}"), ("Tuple(Sub(A, 2), Sub(A, 1), Step(n, For(n, A, B)), Add(B, 1), Add(B, 2))", r"\left(A - 2, A - 1, A, A + 1, \ldots, B, B + 1, B + 2\right)"), ("Lattice(1, tau)", r"\Lambda_{(1, \tau)}"), ("DiscreteLog(n, 2, q)", r"(\epsilon : {2}^{\epsilon} \equiv n \text{ mod }q)"), ("AsymptoticTo(f(n), g(n), n, Infinity)", r"f(n) \sim g(n), \; n \to \infty"), ("Set(CoulombF(l, eta, z), CoulombG(l, eta, z), CoulombH(1, l, eta, z), CoulombH(-1, l, eta, z), CoulombH(omega, l, eta, z))", r"\left\{F_{l,\eta}(z), G_{l,\eta}(z), H^{+}_{l,\eta}(z), H^{-}_{l,\eta}(z), H^{\omega}_{l,\eta}(z)\right\}"), ("Set(Matrices(CC, n), Matrices(CC, n, m))", r"\left\{\operatorname{M}_{n}(\mathbb{C}), \operatorname{M}_{n \times m}(\mathbb{C})\right\}"), ('Set(SloaneA(40, n), SloaneA(12345, n), SloaneA("A553322", n))', r"\left\{\text{A000040}\!\left(n\right), \text{A012345}\!\left(n\right), \text{A553322}\!\left(n\right)\right\}"), ('And(EqualAndElement(x, Pi, RR), EqualNearestDecimal(Pi, Decimal("3.14"), 3))', r"x = \pi \in \mathbb{R} \;\mathbin{\operatorname{and}}\; \pi = 3.14 \;\, {\scriptstyle (\text{nearest } 3 \text{ digits})}"), ("Less(0, Same(Div(1, Sqrt(2)), Div(Sqrt(2), 2)), 1)", r"0 < \frac{1}{\sqrt{2}} = \frac{\sqrt{2}}{2} < 1"), ("Fun(x, Pow(x, 2))", r"x \mapsto {x}^{2}"), ("GeneralizedBernoulliB(n, chi)", r"B_{n, \chi}"), ("HurwitzZeta(s, a, 2)", r"\zeta''\!\left(s, a\right)"), ("Set(StieltjesGamma(n), StieltjesGamma(n, a))", r"\left\{\gamma_{n}, \gamma_{n}\!\left(a\right)\right\}"), ("And(IsHolomorphicOn(f(z), For(z, CC)), IsMeromorphicOn(g(z), For(z, CC)))", r"f(z) \text{ is holomorphic on } z \in \mathbb{C} \;\mathbin{\operatorname{and}}\; g(z) \text{ is meromorphic on } z \in \mathbb{C}"), ("Set(StirlingSeriesRemainder(N, z), LogBarnesGRemainder(N, z))", r"\left\{R_{N}\!\left(z\right), R_{N}\!\left(z\right)\right\}"), ("AnalyticContinuation(f(z), For(z, a, b))", r"\mathop{\text{Continuation}}\limits_{\displaystyle{z: a \rightsquigarrow b}} \, f(z)"), ("AnalyticContinuation(f(z), For(z, CurvePath(g(t), For(t, a, b))))", r"\mathop{\text{Continuation}}\limits_{\displaystyle{z: \left(g(t),\, t : a \rightsquigarrow b\right)}} \, f(z)"), ("BernoulliPolynomial(n, x)", r"B_{n}\!\left(x\right)"), ("Call(f, x)", r"f(x)"), ("CallIndeterminate(f, x, v)", r"f(v)"), ("CartesianProduct(ZZ, QQ)", r"\mathbb{Z} \times \mathbb{Q}"), ("CartesianPower(RR, 3)", r"{\mathbb{R}}^{3}"), ("Characteristic(R)", r"\operatorname{char}(R)"), ("Coefficient(f, x, 2)", r"[{x}^{2}] f"), ("ComplexZeroMultiplicity(f(z), For(z, a))", r"\mathop{\operatorname{ord}}\limits_{z=a} f(z)"), ("Residue(f(z), For(z, a))", r"\mathop{\operatorname{res}}\limits_{z=a} f(z)"), ("ConreyGenerator(q)", r"g_{q}"), ("CoulombC(l, eta)", r"C_{l}\!\left(\eta\right)"), ("CoulombSigma(l, eta)", r"\sigma_{l}\!\left(\eta\right)"), ("Cyclotomic(n, x)", r"\Phi_{n}\!\left(x\right)"), ("DedekindEtaEpsilon(a, b, c, d)", r"\varepsilon(a, b, c, d)"), ("DedekindSum(a, b)", r"s(a, b)"), ("Where(f(Add(x, 1)), Def(f(t), Div(1, t)))", r"f\!\left(x + 1\right)\; \text{ where } f(t) = \frac{1}{t}"), ("Det(Matrix2x2(a, b, c, d))", r"\operatorname{det} \displaystyle{\begin{pmatrix}a & b \\ c & d\end{pmatrix}}"), ("Det(A)", r"\operatorname{det}(A)"), ("f(a, b, Ellipsis, z)", r"f(a, b, \ldots, z)"), ("Equal(DirichletL(DirichletLZero(n, chi), chi), 0)", r"L\!\left(\rho_{n, \chi}, \chi\right) = 0"), ("DirichletGroup(q)", r"G_{q}"), ("Set(ModularGroupFundamentalDomain, ModularLambdaFundamentalDomain)", r"\left\{\mathcal{F}, \mathcal{F}_{\lambda}\right\}"), ("Path(a, b, c, d)", r"a \rightsquigarrow b \rightsquigarrow c \rightsquigarrow d"), ("PolynomialDegree(f)", r"\deg(f)"), ("RootOfUnity(5)", r"\zeta_{5}"), ("SL2Z", r"\operatorname{SL}_2(\mathbb{Z})"), ("UpperHalfPlane", r"\mathbb{H}"), ("XGCD(m, n)", r"\operatorname{xgcd}(m, n)"), ("JacobiThetaQ(3, z, q)", r"\theta_{3}\!\left(z, q\right)"), ("KeiperLiLambda(n)", r"\lambda_{n}"), ("Set(LambertW(z), LambertW(z, n), LambertW(z, n, 1), LambertW(z, n, r))", r"\left\{W(z), W_{n}(z), W'_{n}(z), {W}^{(r)}_{n}(z)\right\}"), ("LandauG(n)", r"g(n)"), ("SquaresR(k, n)", r"r_{k}\!\left(n\right)"), ("ModularGroupAction(gamma, tau)", r"\gamma \circ \tau"), ("Mod(n, p)", r"n \bmod p"), ("LessEqual(0, Step(f(n), For(n, a, b)), 1)", r"0 \le f(a) \le f\!\left(a + 1\right) \le \ldots \le f(b) \le 1"), ("LessEqual(0, Step(f(n), For(n, 1, b)), 1)", r"0 \le f(1) \le f(2) \le \ldots \le f(b) \le 1"), ("Add(LowerGamma(s, z), UpperGamma(s, z))", r"\gamma(s, z) + \Gamma(s, z)"), ("DigammaFunctionZero(n)", r"x_{n}"), ("Set(EulerPolynomial(n, x), HermiteH(n, x), HilbertClassPolynomial(n, x))", r"\left\{E_{n}\!\left(x\right), H_{n}\!\left(x\right), H_{n}\!\left(x\right)\right\}"), ("JacobiThetaEpsilon(j, a, b, c, d)", r"\varepsilon_{j}\!\left(a, b, c, d\right)"), ("JacobiThetaPermutation(j, a, b, c, d)", r"S_{j}\!\left(a, b, c, d\right)"), ("SymmetricPolynomial(k, List(X_(t), For(t, 1, n)))", r"e_{k}\!\left(\left[X_{1}, X_{2}, \ldots, X_{n}\right]\right)"), ("Intersection(A, B)", r"A \cap B"), ("RealAlgebraicNumbers", r"\overline{\mathbb{Q}}_{\mathbb{R}}"), ] def test_latex(fexpr): print("test latex!") fexpr.inject(vars=True) for formula, expected in latex_test_cases: expr = eval(formula, globals(), locals()) latex = expr.latex() if latex != expected: raise AssertionError("%s: got '%s', expected '%s'" % (formula, latex, expected)) def latex_report(fexpr): fexpr.inject(vars=True) formulas = [eval(formula, globals(), locals()) for formula, expected in latex_test_cases] from os.path import expanduser from time import clock fp = open(expanduser("~/Desktop/latex_report.html"), "w") fp.write(""" fexpr to LaTeX test sheet """) output = [formula.latex() for formula in formulas] one_big = fexpr("BigLatex")(*formulas) t1 = clock() one_big_latex = one_big.latex() t2 = clock() fp.write("""

fexpr to LaTeX test sheet

""") fp.write("""

Converted %i formulas (%i leaves, %i bytes) to LaTeX in %f seconds.

""" % (len(formulas), one_big.num_leaves(), one_big.size_bytes(), (t2-t1))) fp.write("""""") fp.write("""""") for formula, latex in zip(formulas, output): fp.write("""""") fp.write("""""" % formula) fp.write("""""" % latex) fp.write("""""" % latex) fp.write("""""") fp.write("""
fexpr Generated LaTeX KaTeX display
%s%s$$%s$$
""") fp.write("""

Untested builtins:

""") s = str(one_big) for c in '-+()_,"': s = s.replace(c, " ") used = set(s.split()) builtins = [name.strip("_") for name in fexpr.builtins()] unused = [name for name in builtins if name not in used] for name in unused: fp.write(name) fp.write(" ") fp.write("""

""") fp.write("""""") fp.close() calcium-0.4.1/qqbar.h000066400000000000000000000330031407704557200144220ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef QQBAR_H #define QQBAR_H #ifdef QQBAR_INLINES_C #define QQBAR_INLINE #else #define QQBAR_INLINE static __inline__ #endif #ifdef __cplusplus extern "C" { #endif #include "flint/fmpz_poly.h" #include "flint/fmpq_poly.h" #include "flint/fmpz_mat.h" #include "flint/fmpq_mat.h" #include "flint/fmpz_mpoly.h" #include "acb.h" #include "calcium.h" #include "fexpr.h" typedef struct { fmpz_poly_struct poly; acb_struct enclosure; } qqbar_struct; typedef qqbar_struct qqbar_t[1]; typedef qqbar_struct * qqbar_ptr; typedef const qqbar_struct * qqbar_srcptr; #define QQBAR_POLY(x) (&((x)->poly)) #define QQBAR_COEFFS(x) ((&((x)->poly))->coeffs) #define QQBAR_ENCLOSURE(x) (&((x)->enclosure)) #define QQBAR_DEFAULT_PREC 128 /* Memory management */ void qqbar_init(qqbar_t res); void qqbar_clear(qqbar_t res); QQBAR_INLINE qqbar_ptr _qqbar_vec_init(slong len) { slong i; qqbar_ptr vec = flint_malloc(len * sizeof(qqbar_struct)); for (i = 0; i < len; i++) qqbar_init(vec + i); return vec; } QQBAR_INLINE void _qqbar_vec_clear(qqbar_ptr vec, slong len) { slong i; for (i = 0; i < len; i++) qqbar_clear(vec + i); flint_free(vec); } /* Assignment */ void qqbar_swap(qqbar_t x, qqbar_t y); void qqbar_set(qqbar_t res, const qqbar_t x); void qqbar_set_si(qqbar_t res, slong x); void qqbar_set_ui(qqbar_t res, ulong x); void qqbar_set_fmpz(qqbar_t res, const fmpz_t x); void qqbar_set_fmpq(qqbar_t res, const fmpq_t x); void qqbar_set_re_im(qqbar_t res, const qqbar_t x, const qqbar_t y); int qqbar_set_d(qqbar_t res, double x); int qqbar_set_re_im_d(qqbar_t res, double x, double y); /* Properties */ QQBAR_INLINE slong qqbar_degree(const qqbar_t x) { return fmpz_poly_degree(QQBAR_POLY(x)); } QQBAR_INLINE int qqbar_is_rational(const qqbar_t x) { return (qqbar_degree(x) == 1); } QQBAR_INLINE int qqbar_is_integer(const qqbar_t x) { return qqbar_is_rational(x) && fmpz_is_one(QQBAR_COEFFS(x) + 1); } QQBAR_INLINE int qqbar_is_algebraic_integer(const qqbar_t x) { return fmpz_is_one(QQBAR_COEFFS(x) + qqbar_degree(x)); } QQBAR_INLINE int qqbar_is_zero(const qqbar_t x) { return qqbar_is_integer(x) && fmpz_is_zero(QQBAR_COEFFS(x)); } QQBAR_INLINE int qqbar_is_one(const qqbar_t x) { return qqbar_is_integer(x) && (fmpz_equal_si(QQBAR_COEFFS(x), -1)); } QQBAR_INLINE int qqbar_is_neg_one(const qqbar_t x) { return qqbar_is_integer(x) && fmpz_is_one(QQBAR_COEFFS(x)); } QQBAR_INLINE int qqbar_is_i(const qqbar_t x) { return (qqbar_degree(x) == 2) && fmpz_is_one(QQBAR_COEFFS(x)) && fmpz_is_zero(QQBAR_COEFFS(x) + 1) && fmpz_is_one(QQBAR_COEFFS(x) + 2) && arf_sgn(arb_midref(acb_imagref(QQBAR_ENCLOSURE(x)))) > 0; } QQBAR_INLINE int qqbar_is_neg_i(const qqbar_t x) { return (qqbar_degree(x) == 2) && fmpz_is_one(QQBAR_COEFFS(x)) && fmpz_is_zero(QQBAR_COEFFS(x) + 1) && fmpz_is_one(QQBAR_COEFFS(x) + 2) && arf_sgn(arb_midref(acb_imagref(QQBAR_ENCLOSURE(x)))) < 0; } int qqbar_sgn_re(const qqbar_t x); int qqbar_sgn_im(const qqbar_t x); QQBAR_INLINE int qqbar_is_real(const qqbar_t x) { return qqbar_sgn_im(x) == 0; } slong qqbar_height_bits(const qqbar_t x); void qqbar_height(fmpz_t res, const qqbar_t x); QQBAR_INLINE int qqbar_within_limits(const qqbar_t x, slong deg_limit, slong bits_limit) { return (deg_limit == 0 || (qqbar_degree(x) <= deg_limit)) && (bits_limit == 0 || (qqbar_height_bits(x) <= bits_limit)); } QQBAR_INLINE int qqbar_binop_within_limits(const qqbar_t x, const qqbar_t y, slong deg_limit, slong bits_limit) { return (deg_limit == 0 || (qqbar_degree(x) * qqbar_degree(y) <= deg_limit)) && (bits_limit == 0 || (qqbar_height_bits(x) + qqbar_height_bits(y) <= bits_limit)); } /* Conversions */ void _qqbar_get_fmpq(fmpz_t num, fmpz_t den, const qqbar_t x); void qqbar_get_fmpq(fmpq_t res, const qqbar_t x); void qqbar_get_fmpz(fmpz_t res, const qqbar_t x); /* Special values */ QQBAR_INLINE void qqbar_zero(qqbar_t res) { qqbar_set_ui(res, 0); } QQBAR_INLINE void qqbar_one(qqbar_t res) { qqbar_set_ui(res, 1); } void qqbar_i(qqbar_t res); void qqbar_phi(qqbar_t res); /* Random generation */ void qqbar_randtest(qqbar_t res, flint_rand_t state, slong deg, slong bits); void qqbar_randtest_real(qqbar_t res, flint_rand_t state, slong deg, slong bits); void qqbar_randtest_nonreal(qqbar_t res, flint_rand_t state, slong deg, slong bits); /* Input and output */ void qqbar_print(const qqbar_t x); void qqbar_printn(const qqbar_t x, slong n); void qqbar_printnd(const qqbar_t x, slong n); /* Comparisons */ int qqbar_equal(const qqbar_t x, const qqbar_t y); int qqbar_equal_fmpq_poly_val(const qqbar_t x, const fmpq_poly_t f, const qqbar_t y); int qqbar_cmp_re(const qqbar_t x, const qqbar_t y); int qqbar_cmp_im(const qqbar_t x, const qqbar_t y); int qqbar_cmpabs_re(const qqbar_t x, const qqbar_t y); int qqbar_cmpabs_im(const qqbar_t x, const qqbar_t y); int qqbar_cmpabs(const qqbar_t x, const qqbar_t y); int qqbar_cmp_root_order(const qqbar_t x, const qqbar_t y); ulong qqbar_hash(const qqbar_t x); /* Complex parts */ void qqbar_conj(qqbar_t res, const qqbar_t x); void qqbar_re(qqbar_t res, const qqbar_t x); void qqbar_im(qqbar_t res, const qqbar_t x); void qqbar_re_im(qqbar_t res1, qqbar_t res2, const qqbar_t x); void qqbar_abs(qqbar_t res, const qqbar_t x); void qqbar_abs2(qqbar_t res, const qqbar_t x); void qqbar_sgn(qqbar_t res, const qqbar_t x); int qqbar_csgn(const qqbar_t x); /* Integer parts */ void qqbar_floor(fmpz_t res, const qqbar_t x); void qqbar_ceil(fmpz_t res, const qqbar_t x); void qqbar_numerator(qqbar_t res, const qqbar_t y); void qqbar_denominator(fmpz_t res, const qqbar_t y); /* Arithmetic */ void qqbar_neg(qqbar_t res, const qqbar_t x); void qqbar_add(qqbar_t res, const qqbar_t x, const qqbar_t y); void qqbar_add_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y); void qqbar_add_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y); void qqbar_add_ui(qqbar_t res, const qqbar_t x, ulong y); void qqbar_add_si(qqbar_t res, const qqbar_t x, slong y); void qqbar_sub(qqbar_t res, const qqbar_t x, const qqbar_t y); void qqbar_sub_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y); void qqbar_sub_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y); void qqbar_sub_ui(qqbar_t res, const qqbar_t x, ulong y); void qqbar_sub_si(qqbar_t res, const qqbar_t x, slong y); void qqbar_fmpq_sub(qqbar_t res, const fmpq_t x, const qqbar_t y); void qqbar_fmpz_sub(qqbar_t res, const fmpz_t x, const qqbar_t y); void qqbar_ui_sub(qqbar_t res, ulong x, const qqbar_t y); void qqbar_si_sub(qqbar_t res, slong x, const qqbar_t y); void qqbar_mul(qqbar_t res, const qqbar_t x, const qqbar_t y); void qqbar_mul_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y); void qqbar_mul_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y); void qqbar_mul_ui(qqbar_t res, const qqbar_t x, ulong y); void qqbar_mul_si(qqbar_t res, const qqbar_t x, slong y); void qqbar_div(qqbar_t res, const qqbar_t x, const qqbar_t y); void qqbar_div_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y); void qqbar_div_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y); void qqbar_div_ui(qqbar_t res, const qqbar_t x, ulong y); void qqbar_div_si(qqbar_t res, const qqbar_t x, slong y); void qqbar_fmpq_div(qqbar_t res, const fmpq_t x, const qqbar_t y); void qqbar_fmpz_div(qqbar_t res, const fmpz_t x, const qqbar_t y); void qqbar_ui_div(qqbar_t res, ulong x, const qqbar_t y); void qqbar_si_div(qqbar_t res, slong x, const qqbar_t y); QQBAR_INLINE void qqbar_sqr(qqbar_t res, const qqbar_t x) { qqbar_mul(res, x, x); } void qqbar_inv(qqbar_t res, const qqbar_t x); void qqbar_mul_2exp_si(qqbar_t res, const qqbar_t x, slong exp); void qqbar_pow_ui(qqbar_t res, const qqbar_t x, ulong e); void qqbar_pow_si(qqbar_t res, const qqbar_t x, slong n); void qqbar_pow_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t n); void qqbar_pow_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t n); int qqbar_pow(qqbar_t res, const qqbar_t x, const qqbar_t e); /* Check if x = (p/q)^(1/n), p > 0 */ int _qqbar_fast_detect_simple_principal_surd(const qqbar_t x); void qqbar_root_ui(qqbar_t res, const qqbar_t x, ulong n); QQBAR_INLINE void qqbar_sqrt(qqbar_t res, const qqbar_t x) { qqbar_root_ui(res, x, 2); } QQBAR_INLINE void qqbar_sqrt_ui(qqbar_t res, ulong x) { qqbar_set_ui(res, x); qqbar_sqrt(res, res); } QQBAR_INLINE void qqbar_rsqrt(qqbar_t res, const qqbar_t x) { qqbar_sqrt(res, x); qqbar_inv(res, res); } void qqbar_fmpq_root_ui(qqbar_t res, const fmpq_t x, ulong b); void qqbar_fmpq_pow_si_ui(qqbar_t res, const fmpq_t x, slong a, ulong b); /* Numerical enclosure */ void qqbar_cache_enclosure(qqbar_t res, slong prec); void qqbar_get_acb(acb_t res, const qqbar_t x, slong prec); void qqbar_get_arb(arb_t res, const qqbar_t x, slong prec); void qqbar_get_arb_re(arb_t res, const qqbar_t x, slong prec); void qqbar_get_arb_im(arb_t res, const qqbar_t x, slong prec); /* Conjugates */ void qqbar_conjugates(qqbar_ptr res, const qqbar_t x); /* Polynomial operations */ void _qqbar_evaluate_fmpq_poly(qqbar_t res, const fmpz * poly, const fmpz_t den, slong len, const qqbar_t x); void qqbar_evaluate_fmpq_poly(qqbar_t res, const fmpq_poly_t poly, const qqbar_t x); void _qqbar_evaluate_fmpz_poly(qqbar_t res, const fmpz * poly, slong len, const qqbar_t x); void qqbar_evaluate_fmpz_poly(qqbar_t res, const fmpz_poly_t poly, const qqbar_t x); int qqbar_evaluate_fmpz_mpoly_iter(qqbar_t res, const fmpz_mpoly_t f, qqbar_srcptr x, slong deg_limit, slong bits_limit, const fmpz_mpoly_ctx_t ctx); int qqbar_evaluate_fmpz_mpoly_horner(qqbar_t res, const fmpz_mpoly_t f, qqbar_srcptr x, slong deg_limit, slong bits_limit, const fmpz_mpoly_ctx_t ctx); int qqbar_evaluate_fmpz_mpoly(qqbar_t res, const fmpz_mpoly_t f, qqbar_srcptr x, slong deg_limit, slong bits_limit, const fmpz_mpoly_ctx_t ctx); #define QQBAR_ROOTS_IRREDUCIBLE 1 #define QQBAR_ROOTS_UNSORTED 2 void qqbar_roots_fmpz_poly(qqbar_ptr res, const fmpz_poly_t poly, int flags); void qqbar_roots_fmpq_poly(qqbar_ptr res, const fmpq_poly_t poly, int flags); void qqbar_eigenvalues_fmpz_mat(qqbar_ptr res, const fmpz_mat_t mat, int flags); void qqbar_eigenvalues_fmpq_mat(qqbar_ptr res, const fmpq_mat_t mat, int flags); /* Roots of unity and trigonometric functions */ void qqbar_root_of_unity(qqbar_t res, slong p, ulong q); int qqbar_is_root_of_unity(slong * p, ulong * q, const qqbar_t x); void qqbar_exp_pi_i(qqbar_t res, slong p, ulong q); void qqbar_cos_pi(qqbar_t res, slong p, ulong q); void qqbar_sin_pi(qqbar_t res, slong p, ulong q); int qqbar_tan_pi(qqbar_t res, slong p, ulong q); int qqbar_cot_pi(qqbar_t res, slong p, ulong q); int qqbar_sec_pi(qqbar_t res, slong p, ulong q); int qqbar_csc_pi(qqbar_t res, slong p, ulong q); int qqbar_log_pi_i(slong * p, ulong * q, const qqbar_t x); int qqbar_atan_pi(slong * p, ulong * q, const qqbar_t x); int qqbar_asin_pi(slong * p, ulong * q, const qqbar_t x); int qqbar_acos_pi(slong * p, ulong * q, const qqbar_t x); int qqbar_acot_pi(slong * p, ulong * q, const qqbar_t x); int qqbar_asec_pi(slong * p, ulong * q, const qqbar_t x); int qqbar_acsc_pi(slong * p, ulong * q, const qqbar_t x); /* Guessing and simplification */ int qqbar_guess(qqbar_t res, const acb_t z, slong max_deg, slong max_bits, int flags, slong prec); int qqbar_express_in_field(fmpq_poly_t res, const qqbar_t alpha, const qqbar_t x, slong max_bits, int flags, slong prec); /* Conversions to radicals and expressions */ void qqbar_get_quadratic(fmpz_t res_a, fmpz_t res_b, fmpz_t res_c, fmpz_t res_q, const qqbar_t x, int factoring); void qqbar_get_fexpr_repr(fexpr_t res, const qqbar_t x); void qqbar_get_fexpr_root_nearest(fexpr_t res, const qqbar_t x); void qqbar_get_fexpr_root_indexed(fexpr_t res, const qqbar_t x); int qqbar_get_fexpr_formula(fexpr_t res, const qqbar_t x, ulong flags); #define QQBAR_FORMULA_GAUSSIANS 1 #define QQBAR_FORMULA_QUADRATICS 2 #define QQBAR_FORMULA_CYCLOTOMICS 4 #define QQBAR_FORMULA_CUBICS 8 #define QQBAR_FORMULA_QUARTICS 16 #define QQBAR_FORMULA_QUINTICS 32 #define QQBAR_FORMULA_DEPRESSION 64 #define QQBAR_FORMULA_DEFLATION 128 #define QQBAR_FORMULA_SEPARATION 256 #define QQBAR_FORMULA_EXP_FORM 2048 #define QQBAR_FORMULA_TRIG_FORM 4096 #define QQBAR_FORMULA_RADICAL_FORM 8192 #define QQBAR_FORMULA_AUTO_FORM 0 #define QQBAR_FORMULA_ALL ((2 * QQBAR_FORMULA_SEPARATION - 1) | QQBAR_FORMULA_AUTO_FORM) int qqbar_set_fexpr(qqbar_t res, const fexpr_t expr); /* Internal functions */ void qqbar_scalar_op(qqbar_t res, const qqbar_t x, const fmpz_t a, const fmpz_t b, const fmpz_t c); void qqbar_fmpz_poly_composed_op(fmpz_poly_t res, const fmpz_poly_t A, const fmpz_poly_t B, int op); void qqbar_binary_op(qqbar_t res, const qqbar_t x, const qqbar_t y, int op); int _qqbar_validate_uniqueness(acb_t res, const fmpz_poly_t poly, const acb_t z, slong max_prec); int _qqbar_validate_existence_uniqueness(acb_t res, const fmpz_poly_t poly, const acb_t z, slong prec); void _qqbar_enclosure_raw(acb_t res, const fmpz_poly_t poly, const acb_t zin, slong prec); void qqbar_enclosure_raw(acb_t res, const qqbar_t x, slong prec); int _qqbar_acb_lindep(fmpz * rel, acb_srcptr vec, slong len, int check, slong prec); #ifdef __cplusplus } #endif #endif calcium-0.4.1/qqbar/000077500000000000000000000000001407704557200142525ustar00rootroot00000000000000calcium-0.4.1/qqbar/abs.c000066400000000000000000000022661407704557200151710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" /* todo: might be worth it to detect p/q * root of unity */ void qqbar_abs(qqbar_t res, const qqbar_t x) { if (qqbar_is_real(x)) { if (qqbar_sgn_re(x) >= 0) qqbar_set(res, x); else qqbar_neg(res, x); } else if (qqbar_is_root_of_unity(NULL, NULL, x)) { qqbar_one(res); } else { qqbar_t t; qqbar_init(t); if (qqbar_sgn_re(x) == 0) { qqbar_i(t); qqbar_mul(res, x, t); if (qqbar_sgn_re(res) < 0) qqbar_neg(res, res); } else { qqbar_conj(t, x); qqbar_mul(t, x, t); qqbar_sqrt(res, t); } qqbar_clear(t); } arb_zero(acb_imagref(QQBAR_ENCLOSURE(res))); } calcium-0.4.1/qqbar/abs2.c000066400000000000000000000020341407704557200152440ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" /* todo: might be worth it to detect p/q * root of unity */ void qqbar_abs2(qqbar_t res, const qqbar_t x) { if (qqbar_is_real(x)) { qqbar_sqr(res, x); } else if (qqbar_is_root_of_unity(NULL, NULL, x)) { qqbar_one(res); } else { qqbar_t t; qqbar_init(t); if (qqbar_sgn_re(x) == 0) { qqbar_i(t); qqbar_mul(res, x, t); qqbar_sqr(res, res); } else { qqbar_conj(t, x); qqbar_mul(res, x, t); } qqbar_clear(t); } arb_zero(acb_imagref(QQBAR_ENCLOSURE(res))); } calcium-0.4.1/qqbar/acb_lindep.c000066400000000000000000000074261407704557200165070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "flint/fmpz_lll.h" #include "qqbar.h" int _qqbar_acb_lindep(fmpz * rel, acb_srcptr vec, slong len, int check, slong prec) { arf_t tmpr, halfr; fmpz_mat_t A; fmpz_lll_t ctx; fmpz_t scale_exp; int nonreal, found; slong i, accuracy; acb_t z2; mag_t max_size, max_rad, tmpmag; for (i = 0; i < len; i++) if (!acb_is_finite(vec + i)) return 0; found = 0; nonreal = 0; for (i = 0; i < len; i++) if (!arb_contains_zero(acb_imagref(vec + i))) nonreal = 1; fmpz_mat_init(A, len, len + 1 + nonreal); fmpz_init(scale_exp); acb_init(z2); arf_init(tmpr); arf_init(halfr); mag_init(max_size); mag_init(max_rad); mag_init(tmpmag); arf_set_d(halfr, 0.5); for (i = 0; i < len; i++) { arf_get_mag(tmpmag, arb_midref(acb_realref(vec + i))); mag_max(max_size, max_size, tmpmag); arf_get_mag(tmpmag, arb_midref(acb_imagref(vec + i))); mag_max(max_size, max_size, tmpmag); mag_max(max_rad, max_rad, arb_radref(acb_realref(vec + i))); mag_max(max_rad, max_rad, arb_radref(acb_imagref(vec + i))); } prec = FLINT_MAX(prec, 2); if (!mag_is_zero(max_size) && !mag_is_zero(max_rad)) { accuracy = _fmpz_sub_small(MAG_EXPREF(max_size), MAG_EXPREF(max_rad)); accuracy = FLINT_MAX(accuracy, 10); prec = FLINT_MIN(prec, accuracy); } if (mag_is_zero(max_size)) { fmpz_zero(scale_exp); /* todo: quick return? */ } else { fmpz_neg(scale_exp, MAG_EXPREF(max_size)); fmpz_add_ui(scale_exp, scale_exp, prec); } /* Using 5% of the bits for checking will provide some protection against spurious relations */ fmpz_sub_ui(scale_exp, scale_exp, FLINT_MAX(10, prec * 0.05)); /* Create matrix */ for (i = 0; i < len; i++) fmpz_one(fmpz_mat_entry(A, i, i)); for (i = 0; i < len; i++) { arf_mul_2exp_fmpz(tmpr, arb_midref(acb_realref(vec + i)), scale_exp); arf_add(tmpr, tmpr, halfr, prec, ARF_RND_NEAR); arf_floor(tmpr, tmpr); arf_get_fmpz(fmpz_mat_entry(A, i, len), tmpr, ARF_RND_NEAR); if (nonreal) { arf_mul_2exp_fmpz(tmpr, arb_midref(acb_imagref(vec + i)), scale_exp); arf_add(tmpr, tmpr, halfr, prec, ARF_RND_NEAR); arf_floor(tmpr, tmpr); arf_get_fmpz(fmpz_mat_entry(A, i, len + 1), tmpr, ARF_RND_NEAR); } } /* LLL reduction */ fmpz_lll_context_init(ctx, 0.75, 0.51, 1, 0); fmpz_lll(A, NULL, ctx); for (i = 0; i < len; i++) fmpz_set(rel + i, fmpz_mat_entry(A, 0, i)); #if 0 flint_printf("rel "); for (i = 0; i < len; i++) { fmpz_print(rel + i); flint_printf(" "); } flint_printf("\n"); #endif /* Heuristic check */ if (check) { for (i = 0; i < len; i++) acb_addmul_fmpz(z2, vec + i, rel + i, prec + 10); found = !_fmpz_vec_is_zero(rel, len) && acb_contains_zero(z2); } else { found = !_fmpz_vec_is_zero(rel, len); } /* if (found) { flint_printf("REL:\n"); fmpz_mat_print_pretty(A); flint_printf("\n\n"); } */ fmpz_mat_clear(A); fmpz_clear(scale_exp); acb_clear(z2); arf_clear(tmpr); arf_clear(halfr); mag_clear(max_size); mag_clear(max_rad); mag_clear(tmpmag); return found; } calcium-0.4.1/qqbar/acos_pi.c000066400000000000000000000014631407704557200160370ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_acos_pi(slong * p, ulong * q, const qqbar_t x) { if (qqbar_asin_pi(p, q, x)) { slong a, b, g; a = *p; b = *q; /* 1/2 - a/b */ a = b - 2 * a; b = 2 * b; g = n_gcd(FLINT_ABS(a), b); if (g != 1) { a /= g; b /= g; } *p = a; *q = b; return 1; } return 0; } calcium-0.4.1/qqbar/acot_pi.c000066400000000000000000000051101407704557200160310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_acot_pi(slong * p, ulong * q, const qqbar_t x) { slong deg = qqbar_degree(x); *p = 0; *q = 1; if (deg == 1) { if (qqbar_is_zero(x)) { *p = 1; *q = 2; return 1; } if (qqbar_is_one(x)) { *p = 1; *q = 4; return 1; } if (qqbar_is_neg_one(x)) { *p = -1; *q = 4; return 1; } return 0; } else if (deg == 2) { fmpz a, b, c; a = QQBAR_COEFFS(x)[0]; b = QQBAR_COEFFS(x)[1]; c = QQBAR_COEFFS(x)[2]; if (a == -3 && b == 0 && c == 1) { *p = qqbar_sgn_re(x); *q = 6; return 1; } if (a == -1 && b == 0 && c == 3) { *p = qqbar_sgn_re(x); *q = 3; return 1; } if (a == -1 && b == 2 && c == 1) { *p = (qqbar_sgn_re(x) == 1) ? 3 : -1; *q = 8; return 1; } if (a == -1 && b == -2 && c == 1) { *p = (qqbar_sgn_re(x) == 1) ? 1 : -3; *q = 8; return 1; } if (a == 1 && b == -4 && c == 1) { /* root is ~0.267 or ~3.73 -- accuracy should not be that bad */ if (arb_contains_si(acb_realref(QQBAR_ENCLOSURE(x)), 1)) flint_abort(); *p = (arf_cmpabs_2exp_si(arb_midref(acb_realref(QQBAR_ENCLOSURE(x))), 0) < 0) ? 5 : 1; *q = 12; return 1; } if (a == 1 && b == 4 && c == 1) { if (arb_contains_si(acb_realref(QQBAR_ENCLOSURE(x)), -1)) flint_abort(); *p = (arf_cmpabs_2exp_si(arb_midref(acb_realref(QQBAR_ENCLOSURE(x))), 0) < 0) ? -5 : -1; *q = 12; return 1; } return 0; } else if ((deg % 2 != 0) || !qqbar_is_real(x)) { return 0; } else { int res; qqbar_t t; qqbar_init(t); qqbar_inv(t, x); res = qqbar_atan_pi(p, q, t); qqbar_clear(t); return res; } } calcium-0.4.1/qqbar/acsc_pi.c000066400000000000000000000013501407704557200160160ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_acsc_pi(slong * p, ulong * q, const qqbar_t x) { if (qqbar_is_zero(x)) { *p = 0; *q = 1; return 0; } else { int res; qqbar_t t; qqbar_init(t); qqbar_inv(t, x); res = qqbar_asin_pi(p, q, t); qqbar_clear(t); return res; } } calcium-0.4.1/qqbar/add.c000066400000000000000000000034461407704557200151550ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_add(qqbar_t res, const qqbar_t x, const qqbar_t y) { if (qqbar_is_zero(x)) { qqbar_set(res, y); } else if (qqbar_is_zero(y)) { qqbar_set(res, x); } else if (qqbar_is_rational(y)) { fmpz_t a, b; fmpz_init(a); fmpz_init(b); _qqbar_get_fmpq(b, a, y); qqbar_scalar_op(res, x, a, b, a); fmpz_clear(a); fmpz_clear(b); } else if (qqbar_is_rational(x)) { fmpz_t a, b; fmpz_init(a); fmpz_init(b); _qqbar_get_fmpq(b, a, x); qqbar_scalar_op(res, y, a, b, a); fmpz_clear(a); fmpz_clear(b); } else { qqbar_binary_op(res, x, y, 0); } } void qqbar_add_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpq(t, y); qqbar_add(res, x, t); qqbar_clear(t); } void qqbar_add_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpz(t, y); qqbar_add(res, x, t); qqbar_clear(t); } void qqbar_add_ui(qqbar_t res, const qqbar_t x, ulong y) { qqbar_t t; qqbar_init(t); qqbar_set_ui(t, y); qqbar_add(res, x, t); qqbar_clear(t); } void qqbar_add_si(qqbar_t res, const qqbar_t x, slong y) { qqbar_t t; qqbar_init(t); qqbar_set_si(t, y); qqbar_add(res, x, t); qqbar_clear(t); } calcium-0.4.1/qqbar/affine_transform.c000066400000000000000000000076061407704557200177520ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "arb_fmpz_poly.h" #include "qqbar.h" static void _fmpq_poly_compose2(fmpz * res, const fmpz * poly1, const fmpz_t den1, slong len1, const fmpz * poly2, const fmpz_t den2, slong len2) { fmpz_t den; slong len; len = (len1 - WORD(1)) * (len2 - WORD(1)) + WORD(1); fmpz_init(den); if (fmpz_is_one(den2)) { _fmpz_poly_compose(res, poly1, len1, poly2, len2); } else { fmpz_t one; fmpz * v = _fmpz_vec_init(len1); fmpz_init(one); fmpz_one(one); _fmpq_poly_rescale(v, den, poly1, den1, len1, one, den2); _fmpz_poly_compose(res, v, len1, poly2, len2); fmpz_clear(one); _fmpz_vec_clear(v, len1); } _fmpz_vec_content(den, res, len); if (fmpz_sgn(res + len - 1) < 0) fmpz_neg(den, den); _fmpz_vec_scalar_divexact_fmpz(res, res, len, den); fmpz_clear(den); } void qqbar_scalar_op(qqbar_t res, const qqbar_t x, const fmpz_t a, const fmpz_t b, const fmpz_t c) { fmpz_poly_t H; fmpz_t one, Gden; fmpz G[2]; acb_t z, t, w; slong d, prec; if (fmpz_is_zero(c)) { flint_printf("qqbar_scalar_op: division by zero\n"); flint_abort(); } /* Special case: set to rational */ if (fmpz_is_zero(a)) { fmpq_t t; fmpq_init(t); fmpq_set_fmpz_frac(t, b, c); qqbar_set_fmpq(res, t); fmpq_clear(t); return; } d = qqbar_degree(x); /* Special case: rational arithmetic */ if (d == 1) { fmpq_t t; fmpq_init(t); fmpz_neg(fmpq_numref(t), QQBAR_POLY(x)->coeffs); fmpz_set(fmpq_denref(t), QQBAR_POLY(x)->coeffs + 1); if (!fmpz_is_one(a)) fmpq_mul_fmpz(t, t, a); if (!fmpz_is_zero(b)) fmpq_add_fmpz(t, t, b); if (!fmpz_is_one(c)) fmpq_div_fmpz(t, t, c); qqbar_set_fmpq(res, t); fmpq_clear(t); return; } fmpz_poly_init2(H, d + 1); fmpz_init(one); fmpz_init(G); fmpz_init(G + 1); fmpz_init(Gden); /* (ax+b)/c -> inverse transformation (-b+cx)/a */ fmpz_one(one); if (fmpz_sgn(a) > 0) { fmpz_neg(G, b); fmpz_set(G + 1, c); fmpz_set(Gden, a); } else { fmpz_set(G, b); fmpz_neg(G + 1, c); fmpz_neg(Gden, a); } _fmpq_poly_compose2(H->coeffs, QQBAR_POLY(x)->coeffs, one, d + 1, G, Gden, 2); _fmpz_poly_set_length(H, d + 1); acb_init(z); acb_init(t); acb_init(w); acb_set(z, QQBAR_ENCLOSURE(x)); for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { _qqbar_enclosure_raw(z, QQBAR_POLY(x), z, prec); if (fmpz_is_one(a)) acb_set(w, z); else if (fmpz_equal_si(a, -1)) acb_neg(w, z); else acb_mul_fmpz(w, z, a, prec); if (!fmpz_is_zero(b)) acb_add_fmpz(w, w, b, prec); if (!fmpz_is_one(c)) { if (fmpz_equal_si(c, -1)) acb_neg(w, w); else acb_div_fmpz(w, w, c, prec); } if (_qqbar_validate_uniqueness(t, H, w, 2 * prec) /* && acb_rel_accuracy_bits(t) >= QQBAR_DEFAULT_PREC / 2 */) { fmpz_poly_set(QQBAR_POLY(res), H); acb_set(QQBAR_ENCLOSURE(res), t); break; } } acb_clear(z); acb_clear(t); acb_clear(w); fmpz_poly_clear(H); fmpz_clear(one); fmpz_clear(G); fmpz_clear(G + 1); fmpz_clear(Gden); } calcium-0.4.1/qqbar/asec_pi.c000066400000000000000000000013501407704557200160200ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_asec_pi(slong * p, ulong * q, const qqbar_t x) { if (qqbar_is_zero(x)) { *p = 0; *q = 1; return 0; } else { int res; qqbar_t t; qqbar_init(t); qqbar_inv(t, x); res = qqbar_acos_pi(p, q, t); qqbar_clear(t); return res; } } calcium-0.4.1/qqbar/asin_pi.c000066400000000000000000000063521407704557200160460ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void best_rational_fast(slong * p, ulong * q, double x, slong N); int qqbar_asin_pi(slong * p, ulong * q, const qqbar_t x) { slong deg = qqbar_degree(x); *p = 0; *q = 0; if (deg == 1) { if (qqbar_is_zero(x)) { *p = 0; *q = 1; return 1; } if (qqbar_is_one(x)) { *p = 1; *q = 2; return 1; } if (qqbar_is_neg_one(x)) { *p = -1; *q = 2; return 1; } if (QQBAR_COEFFS(x)[1] == 2 && QQBAR_COEFFS(x)[0] == -1) { *p = 1; *q = 6; return 1; } if (QQBAR_COEFFS(x)[1] == 2 && QQBAR_COEFFS(x)[0] == 1) { *p = -1; *q = 6; return 1; } return 0; } else if (deg == 2) { fmpz a, b, c; a = QQBAR_COEFFS(x)[0]; b = QQBAR_COEFFS(x)[1]; c = QQBAR_COEFFS(x)[2]; if (a == -3 && b == 0 && c == 4) { *p = qqbar_sgn_re(x); *q = 3; return 1; } if (a == -1 && b == 0 && c == 2) { *p = qqbar_sgn_re(x); *q = 4; return 1; } if (a == -1 && b == 2 && c == 4) { *p = (qqbar_sgn_re(x) == 1) ? 1 : -3; *q = 10; return 1; } if (a == -1 && b == -2 && c == 4) { *p = (qqbar_sgn_re(x) == 1) ? 3 : -1; *q = 10; return 1; } return 0; } else if (!qqbar_is_real(x)) { return 0; } else { slong degq; slong prec; arb_t z, pi; int res; prec = 64; /* More than enough -- the fractions will only ever be tiny */ res = 0; arb_init(z); arb_init(pi); qqbar_get_arb(z, x, prec); if (arf_cmpabs_2exp_si(arb_midref(z), 0) < 0 && arf_cmpabs_2exp_si(arb_midref(z), -20) > 0) { arb_asin(z, z, prec); arb_const_pi(pi, prec); arb_div(z, z, pi, prec); best_rational_fast(p, q, arf_get_d(arb_midref(z), ARF_RND_NEAR), 1000000); arb_mul_ui(z, z, *q, prec); if (arb_contains_si(z, *p)) { if ((*q) % 2 == 1 || (*q) % 4 == 0) degq = n_euler_phi(*q); else degq = n_euler_phi(*q) / 2; if (deg == degq) { qqbar_t v; qqbar_init(v); qqbar_sin_pi(v, *p, *q); res = qqbar_equal(v, x); qqbar_clear(v); } } } arb_clear(z); arb_clear(pi); return res; } } calcium-0.4.1/qqbar/atan_pi.c000066400000000000000000000114331407704557200160330ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void best_rational_fast(slong * p, ulong * q, double x, slong N) { slong a, b, c, d; double m, t, u, eps; if (x > 1.0 || x < 0.0) { double n = floor(x); best_rational_fast(p, q, x - n, N); *p = *p + n * (*q); return; } a = 0; b = 1; c = 1; d = 1; eps = 0.1 / N; if (fabs(x) < eps) { *p = 0; *q = 1; return; } while (b <= N && d <= N) { m = (a + c) / ((double) (b + d)); if (fabs(m - x) < eps) { if (b + d <= N) { *p = a + c; *q = b + d; } else if (d > b) { *p = c; *q = d; } else { *p = a; *q = b; } return; } else { t = a + c; u = b + d; if (x > m) { a = t; b = u; } else { c = t; d = u; } } } if (b > N) { *p = c; *q = d; } else { *p = a; *q = b; } } int qqbar_atan_pi(slong * p, ulong * q, const qqbar_t x) { slong deg = qqbar_degree(x); *p = 0; *q = 1; if (deg == 1) { if (qqbar_is_zero(x)) { *p = 0; *q = 1; return 1; } if (qqbar_is_one(x)) { *p = 1; *q = 4; return 1; } if (qqbar_is_neg_one(x)) { *p = -1; *q = 4; return 1; } return 0; } else if (deg == 2) { fmpz a, b, c; a = QQBAR_COEFFS(x)[0]; b = QQBAR_COEFFS(x)[1]; c = QQBAR_COEFFS(x)[2]; if (a == -3 && b == 0 && c == 1) { *p = qqbar_sgn_re(x); *q = 3; return 1; } if (a == -1 && b == 0 && c == 3) { *p = qqbar_sgn_re(x); *q = 6; return 1; } if (a == -1 && b == 2 && c == 1) { *p = (qqbar_sgn_re(x) == 1) ? 1 : -3; *q = 8; return 1; } if (a == -1 && b == -2 && c == 1) { *p = (qqbar_sgn_re(x) == 1) ? 3 : -1; *q = 8; return 1; } if (a == 1 && b == -4 && c == 1) { /* root is ~0.267 or ~3.73 -- accuracy should not be that bad */ if (arb_contains_si(acb_realref(QQBAR_ENCLOSURE(x)), 1)) flint_abort(); *p = (arf_cmpabs_2exp_si(arb_midref(acb_realref(QQBAR_ENCLOSURE(x))), 0) < 0) ? 1 : 5; *q = 12; return 1; } if (a == 1 && b == 4 && c == 1) { if (arb_contains_si(acb_realref(QQBAR_ENCLOSURE(x)), -1)) flint_abort(); *p = (arf_cmpabs_2exp_si(arb_midref(acb_realref(QQBAR_ENCLOSURE(x))), 0) < 0) ? -1 : -5; *q = 12; return 1; } return 0; } else if ((deg % 2 != 0) || !qqbar_is_real(x)) { return 0; } else { slong degq; slong prec; arb_t z, pi; int res; prec = 64; /* More than enough -- the fractions will only ever be tiny */ res = 0; arb_init(z); arb_init(pi); qqbar_get_arb(z, x, prec); if (arf_cmpabs_2exp_si(arb_midref(z), 20) < 0 && arf_cmpabs_2exp_si(arb_midref(z), -20) > 0) { arb_atan(z, z, prec); arb_const_pi(pi, prec); arb_div(z, z, pi, prec); best_rational_fast(p, q, arf_get_d(arb_midref(z), ARF_RND_NEAR), 1000000); arb_mul_ui(z, z, *q, prec); if (arb_contains_si(z, *p)) { if ((*q) % 4 == 0) degq = n_euler_phi(*q) / 2; else degq = n_euler_phi(*q); if (deg == degq) { qqbar_t v; qqbar_init(v); qqbar_tan_pi(v, *p, *q); res = qqbar_equal(v, x); qqbar_clear(v); } } } arb_clear(z); arb_clear(pi); return res; } } calcium-0.4.1/qqbar/cache_enclosure.c000066400000000000000000000013321407704557200175370ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_cache_enclosure(qqbar_t res, slong prec) { acb_t t; slong want_prec; want_prec = FLINT_MAX(QQBAR_DEFAULT_PREC, prec) * 1.1 + 32; acb_init(t); qqbar_get_acb(t, res, want_prec); if (acb_contains(QQBAR_ENCLOSURE(res), t)) acb_swap(QQBAR_ENCLOSURE(res), t); acb_clear(t); } calcium-0.4.1/qqbar/ceil.c000066400000000000000000000040601407704557200153320ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_ceil(fmpz_t res, const qqbar_t x) { if (qqbar_is_rational(x)) { fmpz_fdiv_q(res, QQBAR_COEFFS(x), QQBAR_COEFFS(x) + 1); fmpz_neg(res, res); } else { arb_t v; arb_init(v); arb_ceil(v, acb_realref(QQBAR_ENCLOSURE(x)), QQBAR_DEFAULT_PREC); if (!arb_get_unique_fmpz(res, v)) { mag_t t; slong size, prec; acb_t z; mag_init(t); acb_init(z); acb_get_mag(t, QQBAR_ENCLOSURE(x)); if (mag_cmp_2exp_si(t, 0) < 0) mag_one(t); size = *MAG_EXPREF(t); prec = FLINT_MAX(QQBAR_DEFAULT_PREC * 2, 2 * size + 32); acb_set(z, QQBAR_ENCLOSURE(x)); _qqbar_enclosure_raw(z, QQBAR_POLY(x), z, prec); arb_ceil(v, acb_realref(z), prec); /* Do an exact computation */ if (!arb_get_unique_fmpz(res, v)) { qqbar_t u; qqbar_init(u); arb_set_d(v, -0.5); arb_add(v, v, acb_realref(z), prec); arb_ceil(v, v, prec); if (!arb_get_unique_fmpz(res, v)) { flint_printf("qqbar_ceil: either ceil(x) or ceil(x-1/2) should evaluate numerically\n"); flint_abort(); } qqbar_set_fmpz(u, res); qqbar_sub(u, x, u); if (qqbar_sgn_re(u) > 0) fmpz_add_ui(res, res, 1); qqbar_clear(u); } mag_clear(t); acb_clear(z); } arb_clear(v); } } calcium-0.4.1/qqbar/clear.c000066400000000000000000000010061407704557200155010ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_clear(qqbar_t res) { fmpz_poly_clear(QQBAR_POLY(res)); acb_clear(QQBAR_ENCLOSURE(res)); } calcium-0.4.1/qqbar/cmp_im.c000066400000000000000000000036511407704557200156670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_cmp_im(const qqbar_t x, const qqbar_t y) { slong prec; acb_t z1, z2; int res; if (!arb_overlaps(acb_imagref(QQBAR_ENCLOSURE(x)), acb_imagref(QQBAR_ENCLOSURE(y)))) { return arf_cmp(arb_midref(acb_imagref(QQBAR_ENCLOSURE(x))), arb_midref(acb_imagref(QQBAR_ENCLOSURE(y)))); } if (qqbar_sgn_im(y) == 0) return qqbar_sgn_im(x); if (qqbar_sgn_im(x) == 0) return -qqbar_sgn_im(y); if (qqbar_equal(x, y)) return 0; { qqbar_t t; qqbar_init(t); qqbar_neg(t, y); qqbar_conj(t, t); res = qqbar_equal(x, t); qqbar_clear(t); if (res == 1) return 0; } acb_init(z1); acb_init(z2); acb_set(z1, QQBAR_ENCLOSURE(x)); acb_set(z2, QQBAR_ENCLOSURE(y)); res = 0; for (prec = QQBAR_DEFAULT_PREC; ; prec *= 2) { _qqbar_enclosure_raw(z1, QQBAR_POLY(x), z1, prec); _qqbar_enclosure_raw(z2, QQBAR_POLY(y), z2, prec); if (!arb_overlaps(acb_imagref(z1), acb_imagref(z2))) { res = arf_cmp(arb_midref(acb_imagref(z1)), arb_midref(acb_imagref(z2))); break; } /* Force an exact computation (may be slow) */ if (prec >= 4 * QQBAR_DEFAULT_PREC) { qqbar_t t; qqbar_init(t); qqbar_sub(t, x, y); res = qqbar_sgn_im(t); qqbar_clear(t); break; } } acb_clear(z1); acb_clear(z2); return res; } calcium-0.4.1/qqbar/cmp_re.c000066400000000000000000000057651407704557200157000ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_cmp_re(const qqbar_t x, const qqbar_t y) { slong prec; acb_t z1, z2; int res, both_real; if (!arb_overlaps(acb_realref(QQBAR_ENCLOSURE(x)), acb_realref(QQBAR_ENCLOSURE(y)))) { return arf_cmp(arb_midref(acb_realref(QQBAR_ENCLOSURE(x))), arb_midref(acb_realref(QQBAR_ENCLOSURE(y)))); } if (qqbar_sgn_re(y) == 0) return qqbar_sgn_re(x); if (qqbar_sgn_re(x) == 0) return -qqbar_sgn_re(y); if (qqbar_degree(x) == 1 && qqbar_degree(y) == 1) { /* Reversed order since the signs are reversed */ return _fmpq_cmp(QQBAR_COEFFS(y), QQBAR_COEFFS(y) + 1, QQBAR_COEFFS(x), QQBAR_COEFFS(x) + 1); } /* Likely complex conjugates */ if (fmpz_poly_equal(QQBAR_POLY(x), QQBAR_POLY(y))) { qqbar_t t; /* Complex conjugate quadratics */ if (qqbar_degree(x) == 2 && !arb_overlaps(acb_imagref(QQBAR_ENCLOSURE(x)), acb_imagref(QQBAR_ENCLOSURE(y)))) return 0; qqbar_init(t); qqbar_conj(t, y); res = qqbar_equal(x, t); qqbar_clear(t); if (res == 1) return 0; } /* Subtraction is a scalar operation and will be quick */ if ((qqbar_degree(x) == 1 || qqbar_degree(y) == 1)) { qqbar_t t; qqbar_init(t); qqbar_sub(t, x, y); res = qqbar_sgn_re(t); qqbar_clear(t); return res; } acb_init(z1); acb_init(z2); acb_set(z1, QQBAR_ENCLOSURE(x)); acb_set(z2, QQBAR_ENCLOSURE(y)); both_real = -1; res = 0; for (prec = QQBAR_DEFAULT_PREC; ; prec *= 2) { _qqbar_enclosure_raw(z1, QQBAR_POLY(x), z1, prec); _qqbar_enclosure_raw(z2, QQBAR_POLY(y), z2, prec); if (!arb_overlaps(acb_realref(z1), acb_realref(z2))) { res = arf_cmp(arb_midref(acb_realref(z1)), arb_midref(acb_realref(z2))); break; } if (both_real == -1) both_real = qqbar_is_real(x) && qqbar_is_real(y); /* Force an exact computation (may be slow) */ /* Todo: tune the cutoff based on degrees, bit sizes. */ /* Todo: use the improved closures we have computed. */ /* Todo: when is it better to compute and compare the real parts? */ if (!both_real && prec >= 4 * QQBAR_DEFAULT_PREC) { qqbar_t t; qqbar_init(t); qqbar_sub(t, x, y); res = qqbar_sgn_re(t); qqbar_clear(t); break; } } acb_clear(z1); acb_clear(z2); return res; } calcium-0.4.1/qqbar/cmp_root_order.c000066400000000000000000000014221407704557200174320ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_cmp_root_order(const qqbar_t x, const qqbar_t y) { int xreal, yreal, cmp; xreal = qqbar_is_real(x); yreal = qqbar_is_real(y); if (xreal != yreal) return xreal ? -1 : 1; cmp = qqbar_cmp_re(x, y); if (cmp != 0) return -cmp; cmp = qqbar_cmpabs_im(x, y); if (cmp != 0) return cmp; return qqbar_sgn_im(y); } calcium-0.4.1/qqbar/cmpabs.c000066400000000000000000000035331407704557200156670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_cmpabs(const qqbar_t x, const qqbar_t y) { slong prec; acb_t z1, z2; arb_t z3, z4; int res; if (qqbar_sgn_im(x) == 0 && qqbar_sgn_im(y) == 0) return qqbar_cmpabs_re(x, y); if (qqbar_sgn_re(x) == 0 && qqbar_sgn_re(y) == 0) return qqbar_cmpabs_im(x, y); { acb_init(z1); acb_init(z2); arb_init(z3); arb_init(z4); acb_set(z1, QQBAR_ENCLOSURE(x)); acb_set(z2, QQBAR_ENCLOSURE(y)); res = 0; for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { _qqbar_enclosure_raw(z1, QQBAR_POLY(x), z1, prec); _qqbar_enclosure_raw(z2, QQBAR_POLY(y), z2, prec); acb_abs(z3, z1, prec); acb_abs(z4, z2, prec); if (!arb_overlaps(z3, z4)) { res = arf_cmpabs(arb_midref(z3), arb_midref(z4)); break; } /* Force an exact computation (may be slow) */ if (prec >= 4 * QQBAR_DEFAULT_PREC) { qqbar_t t, u; qqbar_init(t); qqbar_init(u); qqbar_abs2(t, x); qqbar_abs2(u, y); res = qqbar_cmp_re(t, u); qqbar_clear(t); qqbar_clear(u); break; } } acb_clear(z1); acb_clear(z2); arb_clear(z3); arb_clear(z4); } return res; } calcium-0.4.1/qqbar/cmpabs_im.c000066400000000000000000000032051407704557200163500ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" static int _arb_overlaps_abs(const arb_t x, const arb_t y) { arb_t t, u; *t = *x; *u = *y; if (arf_sgn(arb_midref(t)) < 0) ARF_NEG(arb_midref(t)); if (arf_sgn(arb_midref(u)) < 0) ARF_NEG(arb_midref(u)); return arb_overlaps(t, u); } int qqbar_cmpabs_im(const qqbar_t x, const qqbar_t y) { int sx, sy; if (!_arb_overlaps_abs(acb_imagref(QQBAR_ENCLOSURE(x)), acb_imagref(QQBAR_ENCLOSURE(y)))) { return arf_cmpabs(arb_midref(acb_imagref(QQBAR_ENCLOSURE(x))), arb_midref(acb_imagref(QQBAR_ENCLOSURE(y)))); } sx = qqbar_sgn_im(x); sy = qqbar_sgn_im(y); if (sx == 0 && sy == 0) return 0; if (sy == 0 && sx != 0) return 1; if (sx == 0 && sy != 0) return -1; if (sx > 0 && sy > 0) return qqbar_cmp_im(x, y); if (sx < 0 && sy < 0) return -qqbar_cmp_im(x, y); /* opposite signs */ { int res; qqbar_t t; qqbar_init(t); if (sx > 0) { qqbar_neg(t, y); res = qqbar_cmp_im(x, t); } else { qqbar_neg(t, x); res = qqbar_cmp_im(t, y); } qqbar_clear(t); return res; } } calcium-0.4.1/qqbar/cmpabs_re.c000066400000000000000000000032051407704557200163510ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" static int _arb_overlaps_abs(const arb_t x, const arb_t y) { arb_t t, u; *t = *x; *u = *y; if (arf_sgn(arb_midref(t)) < 0) ARF_NEG(arb_midref(t)); if (arf_sgn(arb_midref(u)) < 0) ARF_NEG(arb_midref(u)); return arb_overlaps(t, u); } int qqbar_cmpabs_re(const qqbar_t x, const qqbar_t y) { int sx, sy; if (!_arb_overlaps_abs(acb_realref(QQBAR_ENCLOSURE(x)), acb_realref(QQBAR_ENCLOSURE(y)))) { return arf_cmpabs(arb_midref(acb_realref(QQBAR_ENCLOSURE(x))), arb_midref(acb_realref(QQBAR_ENCLOSURE(y)))); } sx = qqbar_sgn_re(x); sy = qqbar_sgn_re(y); if (sx == 0 && sy == 0) return 0; if (sy == 0 && sx != 0) return 1; if (sx == 0 && sy != 0) return -1; if (sx > 0 && sy > 0) return qqbar_cmp_re(x, y); if (sx < 0 && sy < 0) return -qqbar_cmp_re(x, y); /* opposite signs */ { int res; qqbar_t t; qqbar_init(t); if (sx > 0) { qqbar_neg(t, y); res = qqbar_cmp_re(x, t); } else { qqbar_neg(t, x); res = qqbar_cmp_re(t, y); } qqbar_clear(t); return res; } } calcium-0.4.1/qqbar/composed_op.c000066400000000000000000000214341407704557200167310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "arb_fmpz_poly.h" #include "qqbar.h" #define OP_ADD 0 #define OP_SUB 1 #define OP_MUL 2 #define OP_DIV 3 static void fmpq_poly_hadamard_product(fmpq_poly_t res, const fmpq_poly_t poly1, const fmpq_poly_t poly2) { slong i, len; len = FLINT_MIN(fmpq_poly_length(poly1), fmpq_poly_length(poly2)); fmpq_poly_fit_length(res, len); for (i = 0; i < len; i++) fmpz_mul(res->coeffs + i, poly1->coeffs + i, poly2->coeffs + i); fmpz_mul(res->den, poly1->den, poly2->den); _fmpq_poly_set_length(res, len); _fmpq_poly_canonicalise(res->coeffs, res->den, len); } static void fmpq_poly_borel_transform(fmpq_poly_t res, const fmpq_poly_t poly) { slong i, len; len = fmpq_poly_length(poly); if (len <= 2) { fmpq_poly_set(res, poly); } else { fmpz_t c; fmpz_init(c); fmpz_one(c); fmpq_poly_fit_length(res, len); for (i = len - 1; i >= 0; i--) { fmpz_mul(res->coeffs + i, poly->coeffs + i, c); if (i > 1) fmpz_mul_ui(c, c, i); } fmpz_mul(fmpq_poly_denref(res), fmpq_poly_denref(poly), c); _fmpq_poly_set_length(res, len); _fmpq_poly_canonicalise(res->coeffs, res->den, len); fmpz_clear(c); } } static void fmpq_poly_inv_borel_transform(fmpq_poly_t res, const fmpq_poly_t poly) { slong i, len; len = fmpq_poly_length(poly); if (len <= 2) { fmpq_poly_set(res, poly); } else { fmpz_t c; fmpz_init(c); fmpz_one(c); fmpq_poly_fit_length(res, len); fmpz_set(fmpq_poly_denref(res), fmpq_poly_denref(poly)); fmpz_set(res->coeffs, poly->coeffs); fmpz_set(res->coeffs + 1, poly->coeffs + 1); for (i = 2; i < len; i++) { fmpz_mul_ui(c, c, i); fmpz_mul(res->coeffs + i, poly->coeffs + i, c); } _fmpq_poly_set_length(res, len); _fmpq_poly_canonicalise(res->coeffs, res->den, len); fmpz_clear(c); } } void qqbar_fmpz_poly_composed_op(fmpz_poly_t res, const fmpz_poly_t A, const fmpz_poly_t B, int op) { slong d1, d2, n, i; fmpq_poly_t P1, P2, P1rev, P1drev, P2rev, P2drev; d1 = fmpz_poly_degree(A); d2 = fmpz_poly_degree(B); if (d1 <= 0 || d2 <= 0) { flint_printf("composed_op: inputs must not be constants\n"); flint_abort(); } n = d1 * d2 + 1; fmpq_poly_init(P1); fmpq_poly_init(P2); fmpq_poly_init(P1rev); fmpq_poly_init(P1drev); fmpq_poly_init(P2rev); fmpq_poly_init(P2drev); fmpq_poly_set_fmpz_poly(P1, A); fmpq_poly_set_fmpz_poly(P2, B); if (op == OP_DIV) { if (fmpz_is_zero(P2->coeffs)) { flint_printf("composed_op: division by zero\n"); flint_abort(); } fmpq_poly_reverse(P2, P2, d2 + 1); } if (op == OP_SUB) for (i = 1; i <= d2; i += 2) fmpz_neg(P2->coeffs + i, P2->coeffs + i); fmpq_poly_reverse(P1rev, P1, d1 + 1); fmpq_poly_derivative(P1drev, P1); fmpq_poly_reverse(P1drev, P1drev, d1); fmpq_poly_reverse(P2rev, P2, d2 + 1); fmpq_poly_derivative(P2drev, P2); fmpq_poly_reverse(P2drev, P2drev, d2); fmpq_poly_div_series(P1, P1drev, P1rev, n); fmpq_poly_div_series(P2, P2drev, P2rev, n); if (op == OP_MUL || op == OP_DIV) { fmpq_poly_hadamard_product(P1, P1, P2); fmpq_poly_shift_right(P1, P1, 1); fmpq_poly_neg(P1, P1); fmpq_poly_integral(P1, P1); } else { fmpq_poly_borel_transform(P1, P1); fmpq_poly_borel_transform(P2, P2); fmpq_poly_mullow(P1, P1, P2, n); fmpq_poly_shift_right(P1, P1, 1); fmpq_poly_inv_borel_transform(P1, P1); fmpq_poly_neg(P1, P1); fmpq_poly_shift_left(P1, P1, 1); } fmpq_poly_exp_series(P1, P1, n); fmpq_poly_reverse(P1, P1, n); fmpq_poly_get_numerator(res, P1); fmpq_poly_clear(P1); fmpq_poly_clear(P2); fmpq_poly_clear(P1rev); fmpq_poly_clear(P1drev); fmpq_poly_clear(P2rev); fmpq_poly_clear(P2drev); } #define TIMING 0 #if TIMING #include "flint/profiler.h" #endif void qqbar_binary_op_without_guess(qqbar_t res, const qqbar_t x, const qqbar_t y, int op) { slong i, prec, found; fmpz_poly_t H; fmpz_poly_factor_t fac; acb_t z1, z2, w, t; fmpz_poly_init(H); fmpz_poly_factor_init(fac); acb_init(z1); acb_init(z2); acb_init(w); acb_init(t); /* flint_printf("BEGIN COMPOSED OP %wd %wd %wd %wd\n", fmpz_poly_degree(QQBAR_POLY(x)), fmpz_poly_max_bits(QQBAR_POLY(x)), fmpz_poly_degree(QQBAR_POLY(y)), fmpz_poly_max_bits(QQBAR_POLY(y))); */ #if TIMING { flint_printf("composed op: "); TIMEIT_ONCE_START qqbar_fmpz_poly_composed_op(H, QQBAR_POLY(x), QQBAR_POLY(y), op); TIMEIT_ONCE_STOP flint_printf("factoring: "); TIMEIT_ONCE_START fmpz_poly_factor(fac, H); TIMEIT_ONCE_STOP } #else qqbar_fmpz_poly_composed_op(H, QQBAR_POLY(x), QQBAR_POLY(y), op); fmpz_poly_factor(fac, H); #endif acb_set(z1, QQBAR_ENCLOSURE(x)); acb_set(z2, QQBAR_ENCLOSURE(y)); /* qqbar_print(x); printf("\n"); qqbar_print(y); printf("\n"); */ for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { /* printf("binop %ld\n", prec); */ _qqbar_enclosure_raw(z1, QQBAR_POLY(x), z1, prec); _qqbar_enclosure_raw(z2, QQBAR_POLY(y), z2, prec); /* acb_printd(z1, 30); printf("\n"); acb_printd(z2, 30); printf("\n"); */ if (op == 0) acb_add(w, z1, z2, prec); else if (op == 1) acb_sub(w, z1, z2, prec); else if (op == 2) acb_mul(w, z1, z2, prec); else acb_div(w, z1, z2, prec); /* Look for potential roots -- we want exactly one */ found = -1; for (i = 0; i < fac->num && found != -2; i++) { arb_fmpz_poly_evaluate_acb(t, fac->p + i, w, prec); if (acb_contains_zero(t)) { if (found == -1) found = i; else found = -2; } } /* printf("found: %ld\n", found); */ /* Check if the enclosure is good enough */ if (found >= 0) { if (_qqbar_validate_uniqueness(t, fac->p + found, w, 2 * prec)) { fmpz_poly_set(QQBAR_POLY(res), fac->p + found); acb_set(QQBAR_ENCLOSURE(res), t); break; } } } fmpz_poly_clear(H); fmpz_poly_factor_clear(fac); acb_clear(z1); acb_clear(z2); acb_clear(w); acb_clear(t); } void qqbar_binary_op(qqbar_t res, const qqbar_t x, const qqbar_t y, int op) { slong dx, dy; dx = qqbar_degree(x); dy = qqbar_degree(y); /* Guess and verify rational result; this could be generalized to higher degree results. */ if (dx >= 4 && dy >= 4 && dx == dy) { qqbar_t t, u; acb_t z; slong prec; int found; found = 0; prec = QQBAR_DEFAULT_PREC; /* Could be set dynamically (with recomputation...) */ qqbar_init(t); qqbar_init(u); acb_init(z); if (op == 0) acb_add(z, QQBAR_ENCLOSURE(x), QQBAR_ENCLOSURE(y), prec); else if (op == 1) acb_sub(z, QQBAR_ENCLOSURE(x), QQBAR_ENCLOSURE(y), prec); else if (op == 2) acb_mul(z, QQBAR_ENCLOSURE(x), QQBAR_ENCLOSURE(y), prec); else if (op == 3) acb_div(z, QQBAR_ENCLOSURE(x), QQBAR_ENCLOSURE(y), prec); if (qqbar_guess(t, z, 1, prec, 0, prec)) { /* x + y = t <=> x = t - y */ /* x - y = t <=> x = t + y */ /* x * y = t <=> x = t / y */ /* x / y = t <=> x = t * y */ if (op == 0) qqbar_sub(u, t, y); else if (op == 1) qqbar_add(u, t, y); else if (op == 2) qqbar_div(u, t, y); else if (op == 3) qqbar_mul(u, t, y); if (qqbar_equal(x, u)) { qqbar_swap(res, t); found = 1; } } qqbar_clear(t); qqbar_clear(u); acb_clear(z); if (found) return; } qqbar_binary_op_without_guess(res, x, y, op); } calcium-0.4.1/qqbar/conj.c000066400000000000000000000010661407704557200153520ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_conj(qqbar_t res, const qqbar_t x) { fmpz_poly_set(QQBAR_POLY(res), QQBAR_POLY(x)); acb_conj(QQBAR_ENCLOSURE(res), QQBAR_ENCLOSURE(x)); } calcium-0.4.1/qqbar/conjugates.c000066400000000000000000000011411407704557200165550ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_conjugates(qqbar_ptr res, const qqbar_t x) { if (qqbar_degree(x) == 1) qqbar_set(res, x); else qqbar_roots_fmpz_poly(res, QQBAR_POLY(x), QQBAR_ROOTS_IRREDUCIBLE); } calcium-0.4.1/qqbar/cos_pi.c000066400000000000000000000035021407704557200156720ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_cos_pi(qqbar_t res, slong p, ulong q) { fmpq_t t; ulong a, b; slong prec; fmpq_init(t); if (q == 0) { flint_printf("qqbar_cos_pi: q = 0\n"); flint_abort(); } fmpq_set_si(t, p, q); fmpq_div_2exp(t, t, 1); fmpz_fdiv_r(fmpq_numref(t), fmpq_numref(t), fmpq_denref(t)); a = fmpz_get_ui(fmpq_numref(t)); b = fmpz_get_ui(fmpq_denref(t)); if (a == 0) { qqbar_one(res); } else if (b == 2) { qqbar_set_si(res, -1); } else if (b == 3) { qqbar_one(res); qqbar_neg(res, res); qqbar_mul_2exp_si(res, res, -1); } else if (b == 4) { qqbar_zero(res); } else if (b == 6) { qqbar_one(res); qqbar_mul_2exp_si(res, res, -1); } else { fmpz_poly_cos_minpoly(QQBAR_POLY(res), b); fmpq_mul_2exp(t, t, 1); for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { arb_cos_pi_fmpq(acb_realref(QQBAR_ENCLOSURE(res)), t, prec); arb_zero(acb_imagref(QQBAR_ENCLOSURE(res))); acb_mul_2exp_si(QQBAR_ENCLOSURE(res), QQBAR_ENCLOSURE(res), 1); if (_qqbar_validate_uniqueness(QQBAR_ENCLOSURE(res), QQBAR_POLY(res), QQBAR_ENCLOSURE(res), prec * 2)) { break; } } qqbar_mul_2exp_si(res, res, -1); } fmpq_clear(t); } calcium-0.4.1/qqbar/cot_pi.c000066400000000000000000000014021407704557200156700ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_cot_pi(qqbar_t res, slong p, ulong q) { slong g; g = n_gcd(FLINT_ABS(p), q); if (g != 1) { p /= g; q /= g; } if (q == 1) { return 0; } else if (q == 2) { qqbar_zero(res); } else { qqbar_tan_pi(res, p, q); qqbar_inv(res, res); } return 1; } calcium-0.4.1/qqbar/csc_pi.c000066400000000000000000000010771407704557200156630ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_csc_pi(qqbar_t res, slong p, ulong q) { qqbar_sin_pi(res, p, q); if (qqbar_is_zero(res)) return 0; qqbar_inv(res, res); return 1; } calcium-0.4.1/qqbar/csgn.c000066400000000000000000000010341407704557200153460ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_csgn(const qqbar_t x) { int re = qqbar_sgn_re(x); if (re != 0) return re; return qqbar_sgn_im(x); } calcium-0.4.1/qqbar/denominator.c000066400000000000000000000010071407704557200167330ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_denominator(fmpz_t res, const qqbar_t y) { fmpz_set(res, QQBAR_COEFFS(y) + qqbar_degree(y)); } calcium-0.4.1/qqbar/div.c000066400000000000000000000074621407704557200152110ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_div(qqbar_t res, const qqbar_t x, const qqbar_t y) { if (qqbar_is_zero(y)) { flint_printf("qqbar_div: division by zero\n"); flint_abort(); } else if (qqbar_is_zero(x)) { qqbar_zero(res); } else if (qqbar_is_one(x)) { qqbar_inv(res, y); } else if (qqbar_is_one(y)) { qqbar_set(res, x); } else if (qqbar_is_neg_one(x)) { qqbar_inv(res, y); qqbar_neg(res, res); } else if (qqbar_is_neg_one(y)) { qqbar_neg(res, x); } else if (qqbar_is_rational(y)) { fmpz_t a, b, c; fmpz_init(a); fmpz_init(b); fmpz_init(c); _qqbar_get_fmpq(c, a, y); qqbar_scalar_op(res, x, a, b, c); fmpz_clear(a); fmpz_clear(b); fmpz_clear(c); } else if (qqbar_is_rational(x)) { fmpz_t a, b, c; fmpz_init(a); fmpz_init(b); fmpz_init(c); _qqbar_get_fmpq(a, c, x); qqbar_inv(res, y); qqbar_scalar_op(res, res, a, b, c); fmpz_clear(a); fmpz_clear(b); fmpz_clear(c); } else if (_qqbar_fast_detect_simple_principal_surd(x) && _qqbar_fast_detect_simple_principal_surd(y)) { /* (p/q)^(1/d) * (r/s)^(1/e) */ fmpq_t t, u; ulong d, e, f, g; d = qqbar_degree(x); e = qqbar_degree(y); g = n_gcd(d, e); f = (d / g) * e; fmpq_init(t); fmpq_init(u); fmpz_neg(fmpq_numref(t), QQBAR_COEFFS(x)); fmpz_set(fmpq_denref(t), QQBAR_COEFFS(x) + d); fmpz_neg(fmpq_numref(u), QQBAR_COEFFS(y)); fmpz_set(fmpq_denref(u), QQBAR_COEFFS(y) + e); fmpq_pow_si(t, t, e / g); fmpq_pow_si(u, u, d / g); fmpq_div(t, t, u); /* todo: recycle the existing enclosures instead of computing a numerical f-th root from scratch */ qqbar_fmpq_root_ui(res, t, f); fmpq_clear(t); fmpq_clear(u); } else { qqbar_binary_op(res, x, y, 3); } } void qqbar_div_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpq(t, y); qqbar_div(res, x, t); qqbar_clear(t); } void qqbar_div_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpz(t, y); qqbar_div(res, x, t); qqbar_clear(t); } void qqbar_div_ui(qqbar_t res, const qqbar_t x, ulong y) { qqbar_t t; qqbar_init(t); qqbar_set_ui(t, y); qqbar_div(res, x, t); qqbar_clear(t); } void qqbar_div_si(qqbar_t res, const qqbar_t x, slong y) { qqbar_t t; qqbar_init(t); qqbar_set_si(t, y); qqbar_div(res, x, t); qqbar_clear(t); } void qqbar_fmpq_div(qqbar_t res, const fmpq_t x, const qqbar_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpq(t, x); qqbar_div(res, t, y); qqbar_clear(t); } void qqbar_fmpz_div(qqbar_t res, const fmpz_t x, const qqbar_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpz(t, x); qqbar_div(res, t, y); qqbar_clear(t); } void qqbar_ui_div(qqbar_t res, ulong x, const qqbar_t y) { qqbar_t t; qqbar_init(t); qqbar_set_ui(t, x); qqbar_div(res, t, y); qqbar_clear(t); } void qqbar_si_div(qqbar_t res, slong x, const qqbar_t y) { qqbar_t t; qqbar_init(t); qqbar_set_si(t, x); qqbar_div(res, t, y); qqbar_clear(t); } calcium-0.4.1/qqbar/eigenvalues_fmpq_mat.c000066400000000000000000000012231407704557200206070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "flint/fmpq_mat.h" #include "qqbar.h" void qqbar_eigenvalues_fmpq_mat(qqbar_ptr res, const fmpq_mat_t mat, int flags) { fmpq_poly_t t; fmpq_poly_init(t); fmpq_mat_charpoly(t, mat); qqbar_roots_fmpq_poly(res, t, flags); fmpq_poly_clear(t); } calcium-0.4.1/qqbar/eigenvalues_fmpz_mat.c000066400000000000000000000012231407704557200206200ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "flint/fmpz_mat.h" #include "qqbar.h" void qqbar_eigenvalues_fmpz_mat(qqbar_ptr res, const fmpz_mat_t mat, int flags) { fmpz_poly_t t; fmpz_poly_init(t); fmpz_mat_charpoly(t, mat); qqbar_roots_fmpz_poly(res, t, flags); fmpz_poly_clear(t); } calcium-0.4.1/qqbar/enclosure_raw.c000066400000000000000000000075121407704557200172730ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "arb_fmpz_poly.h" #include "qqbar.h" void _qqbar_enclosure_raw(acb_t res, const fmpz_poly_t poly, const acb_t zin, slong prec) { slong d, orig_prec, step, acc; fmpz_poly_t deriv; acb_t z, zmid, t, u; if (acb_rel_accuracy_bits(zin) >= prec - 3) { acb_set(res, zin); return; } d = fmpz_poly_degree(poly); if (d == 1) { arb_set_fmpz(acb_realref(res), poly->coeffs); arb_div_fmpz(acb_realref(res), acb_realref(res), poly->coeffs + 1, prec); arb_neg(acb_realref(res), acb_realref(res)); arb_zero(acb_imagref(res)); return; } orig_prec = prec; acc = acb_rel_accuracy_bits(zin); prec = FLINT_MAX(acc, 32) + 10; fmpz_poly_init(deriv); fmpz_poly_derivative(deriv, poly); acb_init(z); acb_init(zmid); acb_init(t); acb_init(u); acb_set(z, zin); for (step = 0; ; step++) { /* printf("trying %ld, %ld\n", step, prec); acb_printn(z, prec, ARB_STR_CONDENSE * 10); printf("\n"); */ if (step > 40 || prec > 1000000000) { flint_printf("qqbar_enclosure_raw: root refinement not converging\n"); flint_abort(); } prec *= 2; /* Interval Newton refinement */ acb_get_mid(zmid, z); arb_fmpz_poly_evaluate_acb(t, poly, zmid, prec); arb_fmpz_poly_evaluate_acb(u, deriv, z, prec); acb_div(t, t, u, prec); acb_sub(t, zmid, t, prec); if (acb_contains(z, t) && acb_rel_accuracy_bits(t) >= 1.1 * orig_prec) { acb_set(res, t); break; } if (acb_contains(z, t) && acb_rel_accuracy_bits(t) > 1.5 * acb_rel_accuracy_bits(z)) { /* Use refined value for next iteration */ acb_set(z, t); } else { /* Newton refinement seems to be converging too slowly -- force a slow recomputation of all roots (this could be improved...) */ acb_ptr roots; slong found, i; /* printf("recompute %ld %ld\n", d, prec); */ roots = _acb_vec_init(d); /* fmpz_poly_print(poly); printf("\n"); */ if (!fmpz_poly_is_squarefree(poly)) { flint_abort(); } arb_fmpz_poly_complex_roots(roots, poly, 0, 2 * prec); /* Check for unique root */ found = -1; for (i = 0; i < d && found != -2; i++) { if (acb_overlaps(roots + i, z)) { if (found == -1) found = i; else found = -2; } } if (found >= 0) acb_set(t, roots + found); _acb_vec_clear(roots, d); if (found >= 0 && acb_rel_accuracy_bits(t) >= 1.1 * orig_prec) { acb_set(res, t); break; } if (found >= 0 && acb_rel_accuracy_bits(t) > 1.5 * acb_rel_accuracy_bits(z) + 1) { /* Use refined value for next iteration */ acb_set(z, t); } } } fmpz_poly_clear(deriv); acb_clear(z); acb_clear(zmid); acb_clear(t); acb_clear(u); } void qqbar_enclosure_raw(acb_t res, const qqbar_t x, slong prec) { _qqbar_enclosure_raw(res, QQBAR_POLY(x), QQBAR_ENCLOSURE(x), prec); } calcium-0.4.1/qqbar/equal.c000066400000000000000000000030631407704557200155270ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_equal(const qqbar_t x, const qqbar_t y) { slong prec; acb_t z1, z2, z3; int res; if (x == y) return 1; if (!fmpz_poly_equal(QQBAR_POLY(x), QQBAR_POLY(y))) return 0; if (qqbar_degree(x) == 1) return 1; if (!acb_overlaps(QQBAR_ENCLOSURE(x), QQBAR_ENCLOSURE(y))) return 0; if (acb_contains(QQBAR_ENCLOSURE(x), QQBAR_ENCLOSURE(y))) return 1; if (acb_contains(QQBAR_ENCLOSURE(y), QQBAR_ENCLOSURE(x))) return 1; acb_init(z1); acb_init(z2); acb_init(z3); acb_set(z1, QQBAR_ENCLOSURE(x)); acb_set(z2, QQBAR_ENCLOSURE(y)); res = 0; for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { _qqbar_enclosure_raw(z1, QQBAR_POLY(x), z1, prec); _qqbar_enclosure_raw(z2, QQBAR_POLY(y), z2, prec); if (!acb_overlaps(z1, z2)) { res = 0; break; } acb_union(z3, z1, z2, prec); if (_qqbar_validate_uniqueness(z3, QQBAR_POLY(x), z3, 2 * prec)) { res = 1; break; } } acb_clear(z1); acb_clear(z2); acb_clear(z3); return res; } calcium-0.4.1/qqbar/equal_fmpq_poly_val.c000066400000000000000000000051161407704557200204600ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "arb_fmpz_poly.h" #include "qqbar.h" /* Algorithm based on Cohen section 4.5.1 */ /* C = A o P mod B */ /* todo: rem P by B initially if larger */ /* todo: brent-kung or something more clever */ void fmpq_poly_compose_fmpz_poly_mod_fmpz_poly(fmpq_poly_t C, const fmpz_poly_t A, const fmpq_poly_t P, const fmpz_poly_t B) { slong i, m; fmpq_poly_t B2; fmpq_poly_init(B2); fmpq_poly_set_fmpz_poly(B2, B); m = fmpz_poly_degree(A); fmpq_poly_set_fmpz(C, A->coeffs + m); for (i = m - 1; i >= 0; i--) { fmpq_poly_mul(C, C, P); fmpq_poly_add_fmpz(C, C, A->coeffs + i); fmpq_poly_rem(C, C, B2); } fmpq_poly_clear(B2); } int qqbar_equal_fmpq_poly_val(const qqbar_t x, const fmpq_poly_t f, const qqbar_t y) { slong prec; acb_t z1, z2, z3; fmpq_poly_t C; int res; /* todo: should this be used for f->length == 2 too? */ if (f->length <= 1 || qqbar_degree(y) == 1) { qqbar_t v; qqbar_init(v); qqbar_evaluate_fmpq_poly(v, f, y); res = qqbar_equal(v, x); qqbar_clear(v); return res; } acb_init(z1); acb_init(z2); acb_init(z3); fmpq_poly_init(C); acb_set(z1, QQBAR_ENCLOSURE(x)); acb_set(z2, QQBAR_ENCLOSURE(y)); res = 0; for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { _qqbar_enclosure_raw(z1, QQBAR_POLY(x), z1, prec); _qqbar_enclosure_raw(z2, QQBAR_POLY(y), z2, prec); _arb_fmpz_poly_evaluate_acb(z3, f->coeffs, f->length, z2, 2 * prec); acb_div_fmpz(z3, z3, f->den, 2 * prec); if (!acb_overlaps(z1, z3)) { res = 0; break; } if (prec == QQBAR_DEFAULT_PREC / 2) { fmpq_poly_compose_fmpz_poly_mod_fmpz_poly(C, QQBAR_POLY(x), f, QQBAR_POLY(y)); if (!fmpq_poly_is_zero(C)) { res = 0; break; } } acb_union(z3, z1, z3, prec); if (_qqbar_validate_uniqueness(z3, QQBAR_POLY(x), z3, 2 * prec)) { res = 1; break; } } acb_clear(z1); acb_clear(z2); acb_clear(z3); fmpq_poly_clear(C); return res; } calcium-0.4.1/qqbar/evaluate_fmpq_poly.c000066400000000000000000000112461407704557200203160ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "antic/nf.h" #include "antic/nf_elem.h" #include "arb_fmpz_poly.h" #include "qqbar.h" void _qqbar_evaluate_fmpq_poly(qqbar_t res, const fmpz * poly, const fmpz_t den, slong len, const qqbar_t x) { slong d = qqbar_degree(x); if (len == 0) { qqbar_zero(res); } else if (len == 1) { if (fmpz_is_one(den)) { qqbar_set_fmpz(res, poly); } else { fmpq_t t; fmpq_init(t); fmpq_set_fmpz_frac(t, poly, den); qqbar_set_fmpq(res, t); fmpq_clear(t); } } else if (qqbar_is_rational(x)) { fmpq_t t, u; fmpq_init(t); fmpq_init(u); qqbar_get_fmpq(u, x); _fmpq_poly_evaluate_fmpq(fmpq_numref(t), fmpq_denref(t), poly, den, len, fmpq_numref(u), fmpq_denref(u)); qqbar_set_fmpq(res, t); fmpq_clear(t); fmpq_clear(u); } else if (len == 2) { qqbar_scalar_op(res, x, poly + 1, poly, den); } else if (len > d) { fmpz * tmp; fmpz_t r, one; slong len2; tmp = _fmpz_vec_init(len); fmpz_init(r); fmpz_init(one); fmpz_one(one); _fmpq_poly_rem(tmp, r, poly, den, len, QQBAR_COEFFS(x), one, d + 1, NULL); len2 = d; while (len2 >= 1 && fmpz_is_zero(tmp + len2 - 1)) len2--; _qqbar_evaluate_fmpq_poly(res, tmp, r, len2, x); fmpz_clear(r); fmpz_clear(one); _fmpz_vec_clear(tmp, d); } else { fmpq_poly_t t, minpoly; nf_t nf; nf_elem_t elem; fmpq_mat_t mat; int is_power; /* todo: detect squaring. x^4, x^8, ...? */ /* todo: other special cases; deflation? */ is_power = _fmpz_vec_is_zero(poly, len - 1); /* nf_init wants an fmpq_poly_t, so mock up one */ t->coeffs = QQBAR_POLY(x)->coeffs; t->den[0] = 1; t->length = QQBAR_POLY(x)->length; t->alloc = QQBAR_POLY(x)->alloc; nf_init(nf, t); nf_elem_init(elem, nf); t->coeffs = (fmpz *) poly; t->length = len; t->den[0] = *den; t->alloc = len; nf_elem_set_fmpq_poly(elem, t, nf); fmpq_mat_init(mat, d, d); nf_elem_rep_mat(mat, elem, nf); fmpq_poly_init(minpoly); fmpq_mat_minpoly(minpoly, mat); fmpq_mat_clear(mat); { fmpz_poly_t A; acb_t z, t, w; slong prec; int pure_real, pure_imag; A->coeffs = minpoly->coeffs; A->length = minpoly->length; A->alloc = A->length; acb_init(z); acb_init(t); acb_init(w); acb_set(z, QQBAR_ENCLOSURE(x)); pure_real = (qqbar_sgn_im(x) == 0); pure_imag = (qqbar_sgn_re(x) == 0); for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { _qqbar_enclosure_raw(z, QQBAR_POLY(x), z, prec); if (pure_real) arb_zero(acb_imagref(z)); if (pure_imag) arb_zero(acb_realref(z)); if (is_power) { acb_pow_ui(w, z, len - 1, prec); if (!fmpz_is_one(poly + len - 1)) acb_mul_fmpz(w, w, poly + len - 1, prec); if (!fmpz_is_one(den)) acb_div_fmpz(w, w, den, prec); } else { _arb_fmpz_poly_evaluate_acb(w, poly, len, z, prec); if (!fmpz_is_one(den)) acb_div_fmpz(w, w, den, prec); } if (_qqbar_validate_uniqueness(t, A, w, 2 * prec)) { fmpz_poly_set(QQBAR_POLY(res), A); acb_set(QQBAR_ENCLOSURE(res), t); break; } } acb_clear(z); acb_clear(t); acb_clear(w); } fmpq_poly_clear(minpoly); nf_elem_clear(elem, nf); nf_clear(nf); } } void qqbar_evaluate_fmpq_poly(qqbar_t res, const fmpq_poly_t poly, const qqbar_t x) { _qqbar_evaluate_fmpq_poly(res, poly->coeffs, poly->den, poly->length, x); } calcium-0.4.1/qqbar/evaluate_fmpz_mpoly.c000066400000000000000000000342301407704557200205020ustar00rootroot00000000000000/* Copyright (C) 2018 Daniel Schultz Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "flint/fmpz_mpoly.h" #include "qqbar.h" /* The conversion to Horner form can be stated as recursive. However, the call stack has depth proportial to the length of the input polynomial in the worst case. Therefore, we must convert it to an iterative algorithm. The proceedure is HornerForm(f): if f is simple to evaluate return eval(f) else choose a variable v and the smallest non zero exponent e appearing in the terms of f write f = q * v^e + r where r is independent of the variable v return HornerForm(q) * v^e + HornerForm(r) */ typedef struct { slong f; slong r; slong v_var; fmpz_t v_exp; /* will be managed as stack grows / shrinks */ int ret; } stack_entry_struct; typedef stack_entry_struct stack_entry_t[1]; int qqbar_add_checked(qqbar_t res, const qqbar_t x, const qqbar_t y, slong deg_limit, slong bits_limit) { if (!qqbar_binop_within_limits(x, y, deg_limit, bits_limit)) return 0; qqbar_add(res, x, y); return 1; } int qqbar_mul_checked(qqbar_t res, const qqbar_t x, const qqbar_t y, slong deg_limit, slong bits_limit) { if (!qqbar_binop_within_limits(x, y, deg_limit, bits_limit)) return 0; qqbar_mul(res, x, y); return 1; } /* todo: special cases; combine with qqbar_pow */ int qqbar_pow_fmpz_checked(qqbar_t res, const qqbar_t x, const fmpz_t y, slong deg_limit, slong bits_limit) { slong n; if (fmpz_is_zero(y)) { qqbar_one(res); return 1; } /* abort? */ if (qqbar_is_zero(x) && fmpz_sgn(y) < 0) return 0; if (qqbar_is_zero(x) || qqbar_is_one(x)) { qqbar_set(res, x); return 1; } if (qqbar_is_neg_one(x)) { if (fmpz_is_even(y)) qqbar_one(res); else qqbar_set(res, x); return 1; } n = *y; if (n < COEFF_MIN || n > COEFF_MAX) return 0; /* todo */ if ((double) FLINT_ABS(n) * qqbar_height_bits(x) > bits_limit) return 0; if (n > 0) { qqbar_pow_ui(res, x, n); } else { qqbar_pow_ui(res, x, -n); qqbar_inv(res, res); } return 1; } /* A = A * X^pow */ /* todo: cache squares, ...? */ static int _qqbar_pmul(qqbar_t A, const qqbar_t X, const fmpz_t pow, qqbar_t T, slong deg_limit, slong bits_limit) { if (fmpz_is_one(pow)) { return qqbar_mul_checked(A, A, X, deg_limit, bits_limit); } else { if (!qqbar_pow_fmpz_checked(T, X, pow, deg_limit, bits_limit)) return 0; return qqbar_mul_checked(A, A, T, deg_limit, bits_limit); } } int qqbar_evaluate_fmpz_mpoly_horner(qqbar_t A, const fmpz_mpoly_t B, qqbar_srcptr C, slong deg_limit, slong bits_limit, const fmpz_mpoly_ctx_t ctxB) { int success = 1; int ret; slong nvars = ctxB->minfo->nvars; slong i, j, k, cur, next, f, r, f_prev, r_prev, v; slong sp, rp; stack_entry_struct * stack; qqbar_struct * regs; qqbar_t temp; slong * rtypes; ulong totalcounts, maxcounts; ulong * counts; slong Blen = B->length; slong * Blist; const fmpz * Bcoeff = B->coeffs; const ulong * Bexp = B->exps; flint_bitcnt_t Bbits = B->bits; slong BN = mpoly_words_per_exp(Bbits, ctxB->minfo); fmpz * Buexp; fmpz * mdegs; fmpz_t score, tz; TMP_INIT; if (Blen == 0) { qqbar_zero(A); return 1; } if (Blen == 1 && fmpz_mpoly_is_fmpz(B, ctxB)) { qqbar_set_fmpz(A, B->coeffs); return 1; } /* flint_printf("========================== HORNER %wd ==========================\n", Blen); */ FLINT_ASSERT(Blen > 0); TMP_START; fmpz_init(score); fmpz_init(tz); /* unpack B exponents */ Buexp = _fmpz_vec_init(nvars*Blen); for (i = 0; i < Blen; i++) mpoly_get_monomial_ffmpz(Buexp + nvars*i, Bexp + BN*i, Bbits, ctxB->minfo); counts = (ulong *) TMP_ALLOC(nvars*sizeof(ulong)); mdegs = _fmpz_vec_init(nvars); /* stack */ sp = -WORD(1); /* start with empty stack */ stack = (stack_entry_struct *) TMP_ALLOC(nvars*(Blen + 1)*sizeof(stack_entry_struct)); Blist = (slong *) TMP_ALLOC(Blen*sizeof(slong)); /* registers of qqbars */ rp = 0; rtypes = (slong *) TMP_ALLOC((nvars + 1)*sizeof(slong)); regs = (qqbar_struct *) TMP_ALLOC(nvars*sizeof(qqbar_struct)); for (i = 0; i < nvars; i++) qqbar_init(regs + i); qqbar_init(temp); /* polynomials will be stored as link lists */ for (i = 0; i + 1 < Blen; i++) Blist[i] = i + 1; Blist[i] = -WORD(1); sp++; fmpz_init((stack + sp)->v_exp); (stack + sp)->ret = 0; (stack + sp)->f = 0; HornerForm: f = (stack + sp)->f; FLINT_ASSERT(f != -WORD(1)); /* f is not supposed to be zero */ /* obtain a count of the number of terms containing each variable */ for (i = 0; i < nvars; i++) { counts[i] = 0; fmpz_set_si(mdegs + i, -WORD(1)); } for (j = f; j != -WORD(1); j = Blist[j]) { for (i = 0; i < nvars; i++) { if (!fmpz_is_zero(Buexp + nvars*j + i )) { counts[i]++; if (fmpz_sgn(mdegs + i) < 0 || fmpz_cmp(mdegs + i, Buexp + nvars*j + i) > 0) { fmpz_set(mdegs + i, Buexp + nvars*j + i); } } } } totalcounts = 0; maxcounts = 0; v = -WORD(1); for (i = 0; i < nvars; i++) { maxcounts = FLINT_MAX(maxcounts, counts[i]); totalcounts += counts[i]; if (counts[i] != 0) v = i; } /* handle simple cases */ if (totalcounts == 0) { FLINT_ASSERT(Blist[f] == -WORD(1)); /* f should have had only one term */ rtypes[rp] = f; goto HornerFormReturn; } else if (totalcounts == 1) { FLINT_ASSERT(!fmpz_is_zero(Buexp + nvars*f + v)); /* this term should not be a scalar */ if (!qqbar_pow_fmpz_checked(regs + rp, C + v, Buexp + nvars*f + v, deg_limit, bits_limit)) { success = 0; } qqbar_mul_fmpz(regs + rp, regs + rp, Bcoeff + f); if (Blist[f] != -WORD(1)) /* if f has a second term */ { /* this term should be a scalar */ FLINT_ASSERT(fmpz_is_zero(Buexp + nvars*Blist[f] + v)); qqbar_add_fmpz(regs + rp, regs + rp, Bcoeff + Blist[f]); } rtypes[rp] = -WORD(1); goto HornerFormReturn; } /* pick best power to pull out */ k = 0; if (maxcounts == 1) { fmpz_set_si(score, -WORD(1)); for (i = 0; i < nvars; i++) { if (counts[i] == 1 && (fmpz_sgn(score) < 0 || fmpz_cmp(mdegs + i, score) < 0)) { FLINT_ASSERT(fmpz_sgn(mdegs + i) > 0); fmpz_set(score, mdegs + i); k = i; } } } else { fmpz_zero(score); for (i = 0; i < nvars; i++) { if (counts[i] > 1) { FLINT_ASSERT(fmpz_sgn(mdegs + i) > 0); fmpz_mul_ui(tz, mdegs + i, counts[i] - 1); if (fmpz_cmp(tz, score) > 0) { fmpz_swap(score, tz); k = i; } } } } /* set variable power v */ (stack + sp)->v_var = k; fmpz_set((stack + sp)->v_exp, mdegs + k); /* scan f and split into q and v with f = q*v + r then set f = q */ r = -WORD(1); cur = f; f_prev = -WORD(1); r_prev = -WORD(1); while (cur != -WORD(1)) { next = Blist[cur]; if (fmpz_is_zero(Buexp + nvars*cur + k)) { if (f_prev == -WORD(1)) f = Blist[cur]; else Blist[f_prev] = Blist[cur]; if (r_prev == -WORD(1)) r = cur; else Blist[r_prev] = cur; Blist[cur] = -WORD(1); r_prev = cur; } else { /* mdegs[k] should be minimum non zero exponent */ fmpz_sub(Buexp + nvars*cur + k, Buexp + nvars*cur + k, mdegs + k); FLINT_ASSERT(fmpz_sgn(Buexp + nvars*cur + k) >= 0); f_prev = cur; } cur = next; } (stack + sp)->r = r; /* convert the quotient */ sp++; fmpz_init((stack + sp)->v_exp); (stack + sp)->ret = 1; (stack + sp)->f = f; goto HornerForm; HornerForm1: /* convert the remainder */ r = (stack + sp)->r; if (r != -WORD(1)) { /* remainder is non zero */ rp++; FLINT_ASSERT(0 <= rp && rp <= nvars); sp++; fmpz_init((stack + sp)->v_exp); (stack + sp)->ret = 2; (stack + sp)->f = r; goto HornerForm; HornerForm2: if (rtypes[rp - 1] == -WORD(1) && rtypes[rp] == -WORD(1)) { /* both quotient and remainder are polynomials */ if (!_qqbar_pmul(regs + rp - 1, C + (stack + sp)->v_var, (stack + sp)->v_exp, temp, deg_limit, bits_limit)) { success = 0; } if (!qqbar_add_checked(temp, regs + rp - 1, regs + rp, deg_limit, bits_limit)) success = 0; qqbar_swap(temp, regs + rp - 1); } else if (rtypes[rp - 1] == -WORD(1) && rtypes[rp] != -WORD(1)) { /* quotient is a polynomial, remainder is a scalar */ if (!_qqbar_pmul(regs + rp - 1, C + (stack + sp)->v_var, (stack + sp)->v_exp, temp, deg_limit, bits_limit)) { success = 0; } qqbar_add_fmpz(regs + rp - 1, regs + rp - 1, Bcoeff + rtypes[rp]); /* todo: check bits_limit */ } else if (rtypes[rp - 1] != -WORD(1) && rtypes[rp] == -WORD(1)) { /* quotient is a scalar, remainder is a polynomial */ if (!qqbar_pow_fmpz_checked(temp, C + (stack + sp)->v_var, (stack + sp)->v_exp, deg_limit, bits_limit)) { success = 0; } qqbar_mul_fmpz(temp, temp, Bcoeff + rtypes[rp - 1]); if (!qqbar_add_checked(regs + rp - 1, temp, regs + rp, deg_limit, bits_limit)) success = 0; } else { /* quotient is a scalar, remainder is a scalar */ FLINT_ASSERT(0); /* this should have been handled by simple case */ } rp--; FLINT_ASSERT(0 <= rp && rp <= nvars); } else { /* remainder is zero */ FLINT_ASSERT(rtypes[rp] == -WORD(1)); /* quotient is not a scalar */ /* quotient is a polynomial */ if (!_qqbar_pmul(regs + rp, C + (stack + sp)->v_var, (stack + sp)->v_exp, temp, deg_limit, bits_limit)) { success = 0; } } rtypes[rp] = -WORD(1); HornerFormReturn: if (!success) { while (sp >= 0) { fmpz_clear((stack + sp)->v_exp); sp--; } goto cleanup; } ret = (stack + sp)->ret; fmpz_clear((stack + sp)->v_exp); sp--; if (ret == 1) goto HornerForm1; if (ret == 2) goto HornerForm2; FLINT_ASSERT(rp == 0); FLINT_ASSERT(sp == -WORD(1)); if (rtypes[rp] == -WORD(1)) { qqbar_swap(A, regs + rp); } else { qqbar_set_fmpz(A, Bcoeff + rtypes[rp]); } cleanup: for (i = 0; i < nvars; i++) qqbar_clear(regs + i); qqbar_clear(temp); fmpz_clear(score); fmpz_clear(tz); _fmpz_vec_clear(mdegs, nvars); _fmpz_vec_clear(Buexp, nvars*Blen); TMP_END; return success; } int qqbar_evaluate_fmpz_mpoly_iter(qqbar_t res, const fmpz_mpoly_t pol, qqbar_srcptr x, slong deg_limit, slong bits_limit, const fmpz_mpoly_ctx_t ctx) { slong i, j, len, nvars; qqbar_t s, t, u; ulong * exp; int success; len = fmpz_mpoly_length(pol, ctx); if (len == 0) { qqbar_zero(res); return 1; } if (len == 1 && fmpz_mpoly_is_fmpz(pol, ctx)) { qqbar_set_fmpz(res, pol->coeffs); return 1; } success = 0; nvars = ctx->minfo->nvars; exp = flint_malloc(sizeof(ulong) * nvars); qqbar_init(s); qqbar_init(t); qqbar_init(u); for (i = 0; i < len; i++) { fmpz_mpoly_get_term_exp_ui(exp, pol, i, ctx); qqbar_one(t); for (j = 0; j < nvars; j++) { if (exp[j] == 1) { if (!qqbar_binop_within_limits(t, x + j, deg_limit, bits_limit)) goto cleanup; qqbar_mul(t, t, x + j); } else if (exp[j] >= 2) { if ((double) qqbar_height_bits(x + j) * (double) exp[j] > bits_limit) goto cleanup; qqbar_pow_ui(u, x + j, exp[j]); if (!qqbar_binop_within_limits(t, u, deg_limit, bits_limit)) goto cleanup; qqbar_mul(t, t, u); } } qqbar_mul_fmpz(t, t, pol->coeffs + i); if (!qqbar_binop_within_limits(s, t, deg_limit, bits_limit)) goto cleanup; qqbar_add(s, s, t); } success = 1; qqbar_swap(res, s); cleanup: flint_free(exp); qqbar_clear(s); qqbar_clear(t); qqbar_clear(u); return success; } int qqbar_evaluate_fmpz_mpoly(qqbar_t res, const fmpz_mpoly_t f, qqbar_srcptr x, slong deg_limit, slong bits_limit, const fmpz_mpoly_ctx_t ctx) { return qqbar_evaluate_fmpz_mpoly_horner(res, f, x, deg_limit, bits_limit, ctx); } calcium-0.4.1/qqbar/evaluate_fmpz_poly.c000066400000000000000000000014621407704557200203260ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "arb_fmpz_poly.h" #include "qqbar.h" void _qqbar_evaluate_fmpz_poly(qqbar_t res, const fmpz * poly, slong len, const qqbar_t x) { fmpz_t den; fmpz_init(den); fmpz_one(den); _qqbar_evaluate_fmpq_poly(res, poly, den, len, x); fmpz_clear(den); } void qqbar_evaluate_fmpz_poly(qqbar_t res, const fmpz_poly_t poly, const qqbar_t x) { _qqbar_evaluate_fmpz_poly(res, poly->coeffs, poly->length, x); } calcium-0.4.1/qqbar/exp_pi_i.c000066400000000000000000000007701407704557200162160ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_exp_pi_i(qqbar_t res, slong p, ulong q) { qqbar_root_of_unity(res, p, q * 2); } calcium-0.4.1/qqbar/express_in_field.c000066400000000000000000000030001407704557200177310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_express_in_field(fmpq_poly_t res, const qqbar_t alpha, const qqbar_t x, slong max_bits, int flags, slong prec) { slong d, dx; acb_ptr vec; acb_t z; int found; d = qqbar_degree(alpha); dx = qqbar_degree(x); if (dx == 1) { fmpq_t t; fmpq_init(t); qqbar_get_fmpq(t, x); fmpq_poly_set_fmpq(res, t); fmpq_clear(t); return 1; } found = 0; if (d % dx != 0 || (qqbar_is_real(alpha) && !qqbar_is_real(x))) return 0; acb_init(z); vec = _acb_vec_init(d + 1); qqbar_get_acb(z, alpha, prec); _acb_vec_set_powers(vec, z, d, prec); qqbar_get_acb(vec + d, x, prec); fmpq_poly_fit_length(res, d + 1); if (_qqbar_acb_lindep(res->coeffs, vec, d + 1, 1, prec) && !fmpz_is_zero(res->coeffs + d)) { fmpz_neg(res->den, res->coeffs + d); _fmpq_poly_set_length(res, d); _fmpq_poly_normalise(res); fmpq_poly_canonicalise(res); found = qqbar_equal_fmpq_poly_val(x, res, alpha); } acb_clear(z); _acb_vec_clear(vec, d + 1); return found; } calcium-0.4.1/qqbar/floor.c000066400000000000000000000040661407704557200155450ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_floor(fmpz_t res, const qqbar_t x) { if (qqbar_is_rational(x)) { fmpz_cdiv_q(res, QQBAR_COEFFS(x), QQBAR_COEFFS(x) + 1); fmpz_neg(res, res); } else { arb_t v; arb_init(v); arb_floor(v, acb_realref(QQBAR_ENCLOSURE(x)), QQBAR_DEFAULT_PREC); if (!arb_get_unique_fmpz(res, v)) { mag_t t; slong size, prec; acb_t z; mag_init(t); acb_init(z); acb_get_mag(t, QQBAR_ENCLOSURE(x)); if (mag_cmp_2exp_si(t, 0) < 0) mag_one(t); size = *MAG_EXPREF(t); prec = FLINT_MAX(QQBAR_DEFAULT_PREC * 2, 2 * size + 32); acb_set(z, QQBAR_ENCLOSURE(x)); _qqbar_enclosure_raw(z, QQBAR_POLY(x), z, prec); arb_floor(v, acb_realref(z), prec); /* Do an exact computation */ if (!arb_get_unique_fmpz(res, v)) { qqbar_t u; qqbar_init(u); arb_set_d(v, 0.5); arb_add(v, v, acb_realref(z), prec); arb_floor(v, v, prec); if (!arb_get_unique_fmpz(res, v)) { flint_printf("qqbar_floor: either floor(x) or floor(x+1/2) should evaluate numerically\n"); flint_abort(); } qqbar_set_fmpz(u, res); qqbar_sub(u, x, u); if (qqbar_sgn_re(u) < 0) fmpz_sub_ui(res, res, 1); qqbar_clear(u); } mag_clear(t); acb_clear(z); } arb_clear(v); } } calcium-0.4.1/qqbar/fmpq_pow_si_ui.c000066400000000000000000000020541407704557200174370ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_fmpq_pow_si_ui(qqbar_t res, const fmpq_t x, slong a, ulong b) { if (b == 0) flint_abort(); if (a == 0) { qqbar_one(res); } else if (a == 1) { qqbar_fmpq_root_ui(res, x, b); } else if (fmpq_sgn(x) >= 0) { fmpq_t t; fmpq_init(t); fmpq_pow_si(t, x, a); qqbar_fmpq_root_ui(res, t, b); fmpq_clear(t); } else { qqbar_fmpq_root_ui(res, x, b); if (a > 0) { qqbar_pow_ui(res, res, a); } else { qqbar_inv(res, res); qqbar_pow_ui(res, res, -a); } } } calcium-0.4.1/qqbar/fmpq_root_ui.c000066400000000000000000000066421407704557200171310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" static int check_root(fmpz_t p, const fmpz_t x, fmpz_t t, ulong d) { if (fmpz_is_one(x)) { fmpz_one(p); return 1; } else if (d == 2) { fmpz_sqrtrem(p, t, x); return fmpz_is_zero(t); } else { /* todo: need a rootrem function */ fmpz_root(p, x, d); fmpz_pow_ui(t, p, d); return fmpz_equal(t, x); } } void qqbar_fmpq_root_ui(qqbar_t res, const fmpq_t x, ulong b) { ulong d; fmpz_t p, q, t; if (b == 0) flint_abort(); if (b == 1 || fmpq_is_zero(x) || fmpq_is_one(x)) { qqbar_set_fmpq(res, x); return; } if (b == 2) { if (fmpz_is_square(fmpq_numref(x)) && fmpz_is_square(fmpq_denref(x))) { fmpz_poly_fit_length(QQBAR_POLY(res), 2); _fmpz_poly_set_length(QQBAR_POLY(res), 2); fmpz_sqrt(QQBAR_COEFFS(res) + 0, fmpq_numref(x)); fmpz_neg(QQBAR_COEFFS(res) + 0, QQBAR_COEFFS(res) + 0); fmpz_sqrt(QQBAR_COEFFS(res) + 1, fmpq_denref(x)); acb_set_fmpz(QQBAR_ENCLOSURE(res), QQBAR_COEFFS(res) + 0); acb_neg(QQBAR_ENCLOSURE(res), QQBAR_ENCLOSURE(res)); acb_div_fmpz(QQBAR_ENCLOSURE(res), QQBAR_ENCLOSURE(res), QQBAR_COEFFS(res) + 1, QQBAR_DEFAULT_PREC); } else { fmpz_poly_fit_length(QQBAR_POLY(res), 3); _fmpz_poly_set_length(QQBAR_POLY(res), 3); fmpz_set(QQBAR_COEFFS(res) + 0, fmpq_numref(x)); fmpz_neg(QQBAR_COEFFS(res) + 0, QQBAR_COEFFS(res) + 0); fmpz_zero(QQBAR_COEFFS(res) + 1); fmpz_set(QQBAR_COEFFS(res) + 2, fmpq_denref(x)); acb_set_fmpq(QQBAR_ENCLOSURE(res), x, QQBAR_DEFAULT_PREC); acb_sqrt(QQBAR_ENCLOSURE(res), QQBAR_ENCLOSURE(res), QQBAR_DEFAULT_PREC); } return; } if (fmpq_sgn(x) < 0) { qqbar_set_fmpq(res, x); qqbar_root_ui(res, res, b); return; } fmpz_init(p); fmpz_init(q); fmpz_init(t); for (d = b; d >= 1; d--) { if (d == 1) { fmpz_set(p, fmpq_numref(x)); fmpz_set(q, fmpq_denref(x)); } else if (b % d == 0) { if (check_root(p, fmpq_numref(x), t, d) && check_root(q, fmpq_denref(x), t, d)) { b /= d; break; } } } fmpz_poly_set_fmpz(QQBAR_POLY(res), p); fmpz_poly_neg(QQBAR_POLY(res), QQBAR_POLY(res)); fmpz_poly_set_coeff_fmpz(QQBAR_POLY(res), b, q); arb_zero(acb_imagref(QQBAR_ENCLOSURE(res))); arb_set_fmpz(acb_realref(QQBAR_ENCLOSURE(res)), p); arb_div_fmpz(acb_realref(QQBAR_ENCLOSURE(res)), acb_realref(QQBAR_ENCLOSURE(res)), q, QQBAR_DEFAULT_PREC); if (b != 1) arb_root_ui(acb_realref(QQBAR_ENCLOSURE(res)), acb_realref(QQBAR_ENCLOSURE(res)), b, QQBAR_DEFAULT_PREC); if (!arb_is_positive(acb_realref(QQBAR_ENCLOSURE(res)))) flint_abort(); fmpz_clear(p); fmpz_clear(q); fmpz_clear(t); } calcium-0.4.1/qqbar/get_acb.c000066400000000000000000000052251407704557200160060ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" /* Todo: could special-case quadratics, in particular Gaussian rationals */ void qqbar_get_acb(acb_t res, const qqbar_t x, slong prec) { if (qqbar_degree(x) == 1) { arb_set_fmpz(acb_realref(res), QQBAR_COEFFS(x)); arb_div_fmpz(acb_realref(res), acb_realref(res), QQBAR_COEFFS(x) + 1, prec); arb_neg(acb_realref(res), acb_realref(res)); arb_zero(acb_imagref(res)); } else { arb_t t; fmpz_t n; slong wp; int imag_zero, real_zero; imag_zero = (qqbar_sgn_im(x) == 0); real_zero = (qqbar_sgn_re(x) == 0); acb_set(res, QQBAR_ENCLOSURE(x)); for (wp = prec + 30; ; wp *= 2) { _qqbar_enclosure_raw(res, QQBAR_POLY(x), res, wp); if (imag_zero) arb_zero(acb_imagref(res)); if (real_zero) arb_zero(acb_realref(res)); if (arb_rel_accuracy_bits(acb_realref(res)) > prec + 5 && arb_rel_accuracy_bits(acb_imagref(res)) > prec + 5) break; } /* Detect exact (dyadic real/imag parts) */ arb_init(t); fmpz_init(n); arb_mul_2exp_si(t, acb_realref(res), wp); if (!arb_is_exact(t) && arb_get_unique_fmpz(n, t)) { qqbar_t u; qqbar_init(u); qqbar_set_fmpz(u, n); qqbar_mul_2exp_si(u, u, wp); qqbar_sub(u, x, u); if (qqbar_sgn_re(u) == 0) { arb_set_fmpz(acb_realref(res), n); arb_mul_2exp_si(acb_realref(res), acb_realref(res), wp); } qqbar_clear(u); } arb_mul_2exp_si(t, acb_imagref(res), wp); if (!arb_is_exact(t) && arb_get_unique_fmpz(n, t)) { qqbar_t u; qqbar_init(u); qqbar_i(u); qqbar_mul_fmpz(u, u, n); qqbar_mul_2exp_si(u, u, wp); qqbar_sub(u, x, u); if (qqbar_sgn_im(u) == 0) { arb_set_fmpz(acb_imagref(res), n); arb_mul_2exp_si(acb_imagref(res), acb_imagref(res), wp); } qqbar_clear(u); } acb_set_round(res, res, prec); arb_clear(t); fmpz_clear(n); } } calcium-0.4.1/qqbar/get_arb.c000066400000000000000000000012741407704557200160250ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_get_arb(arb_t res, const qqbar_t x, slong prec) { if (qqbar_sgn_im(x) == 0) { acb_t t; acb_init(t); qqbar_get_acb(t, x, prec); arb_swap(res, acb_realref(t)); acb_clear(t); } else { arb_indeterminate(res); } } calcium-0.4.1/qqbar/get_arb_im.c000066400000000000000000000012661407704557200165130ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_get_arb_im(arb_t res, const qqbar_t x, slong prec) { if (qqbar_sgn_im(x) == 0) { arb_zero(res); } else { acb_t t; acb_init(t); qqbar_get_acb(t, x, prec); arb_swap(res, acb_imagref(t)); acb_clear(t); } } calcium-0.4.1/qqbar/get_arb_re.c000066400000000000000000000012661407704557200165140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_get_arb_re(arb_t res, const qqbar_t x, slong prec) { if (qqbar_sgn_re(x) == 0) { arb_zero(res); } else { acb_t t; acb_init(t); qqbar_get_acb(t, x, prec); arb_swap(res, acb_realref(t)); acb_clear(t); } } calcium-0.4.1/qqbar/get_fexpr.c000066400000000000000000000605671407704557200164170ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "arb_fmpz_poly.h" #include "acb_poly.h" #include "fexpr_builtin.h" #include "qqbar.h" static ulong _deflation(const fmpz * poly, slong len) { fmpz_poly_t t; t->alloc = t->length = len; t->coeffs = (fmpz *) poly; return arb_fmpz_poly_deflation(t); } void fexpr_set_arb(fexpr_t res, const arb_t x) { fexpr_t mid, rad, h; arf_t r; fexpr_init(mid); fexpr_init(rad); fexpr_init(h); fexpr_set_symbol_builtin(h, FEXPR_RealBall); fexpr_set_arf(mid, arb_midref(x)); arf_init_set_mag_shallow(r, arb_radref(x)); fexpr_set_arf(rad, r); fexpr_call2(res, h, mid, rad); fexpr_clear(mid); fexpr_clear(rad); fexpr_clear(h); } void fexpr_set_acb(fexpr_t res, const acb_t x) { if (arb_is_zero(acb_imagref(x))) { fexpr_set_arb(res, acb_realref(x)); } else if (arb_is_zero(acb_realref(x))) { fexpr_t v, i; fexpr_init(v); fexpr_init(i); fexpr_set_arb(v, acb_imagref(x)); fexpr_set_symbol_builtin(i, FEXPR_NumberI); fexpr_mul(res, v, i); fexpr_clear(v); fexpr_clear(i); } else { fexpr_t r, v, i; fexpr_init(r); fexpr_init(v); fexpr_init(i); fexpr_set_arb(v, acb_imagref(x)); fexpr_set_symbol_builtin(i, FEXPR_NumberI); fexpr_mul(r, v, i); fexpr_set_arb(v, acb_realref(x)); fexpr_add(res, v, r); fexpr_clear(r); fexpr_clear(v); fexpr_clear(i); } } /* todo: better code (no temporaries) */ void fexpr_set_list_fmpz_poly(fexpr_t res, const fmpz_poly_t poly) { fexpr_struct * coeffs; fexpr_t t; slong i, len; len = poly->length; coeffs = _fexpr_vec_init(len); fexpr_init(t); for (i = 0; i < len; i++) fexpr_set_fmpz(coeffs + i, poly->coeffs + i); fexpr_set_symbol_builtin(t, FEXPR_List); fexpr_call_vec(res, t, coeffs, len); _fexpr_vec_clear(coeffs, len); fexpr_clear(t); } void qqbar_get_fexpr_repr(fexpr_t res, const qqbar_t x) { slong j, d; /* todo: better fexpr construction code */ fexpr_struct * coeffs; fexpr_t t, u, v, w; d = qqbar_degree(x); coeffs = _fexpr_vec_init(d + 1); fexpr_init(t); fexpr_init(u); fexpr_init(v); fexpr_init(w); for (j = 0; j <= d; j++) fexpr_set_fmpz(coeffs + j, QQBAR_COEFFS(x) + j); fexpr_set_symbol_builtin(u, FEXPR_List); fexpr_call_vec(t, u, coeffs, d + 1); fexpr_set_symbol_builtin(v, FEXPR_AlgebraicNumberSerialized); fexpr_set_acb(u, QQBAR_ENCLOSURE(x)); fexpr_call2(res, v, t, u); _fexpr_vec_clear(coeffs, d + 1); fexpr_clear(t); fexpr_clear(u); fexpr_clear(v); fexpr_clear(w); } void _qqbar_get_fexpr_root_nearest(fexpr_t res, const fmpz_poly_t poly, const char * re_s, const char * im_s) { fexpr_t Decimal, a, b, I, s; fexpr_init(Decimal); fexpr_init(a); fexpr_init(b); fexpr_init(I); fexpr_init(s); fexpr_set_symbol_builtin(Decimal, FEXPR_Decimal); if (re_s == NULL && im_s == NULL) { fexpr_set_string(s, "0.0"); fexpr_call1(a, Decimal, s); } else { if (re_s != NULL) { fexpr_set_string(s, re_s); fexpr_call1(a, Decimal, s); } if (im_s != NULL) { fexpr_set_string(s, im_s); fexpr_call1(b, Decimal, s); fexpr_set_symbol_builtin(I, FEXPR_NumberI); fexpr_mul(s, b, I); fexpr_swap(b, s); } } if (im_s == NULL) fexpr_swap(s, a); else if (re_s == NULL) fexpr_swap(s, b); else fexpr_add(s, a, b); fexpr_set_list_fmpz_poly(b, poly); fexpr_set_symbol_builtin(a, FEXPR_PolynomialRootNearest); fexpr_call2(res, a, b, s); fexpr_clear(Decimal); fexpr_clear(a); fexpr_clear(b); fexpr_clear(I); fexpr_clear(s); } void qqbar_get_decimal_root_nearest(char ** re_s, char ** im_s, const qqbar_t x, slong default_digits) { acb_t z, point, delta; acb_poly_t poly; arb_t lhs, rhs, R, Rpow, tmpr; slong k, d, digits, prec, wp; int success; int imag_zero, real_zero; d = qqbar_degree(x); /* For rational numbers, any numerical approximation will suffice */ if (d == 1) { arb_t t; arb_init(t); digits = default_digits; qqbar_get_arb(t, x, 3.333 * digits + 10); re_s[0] = arb_get_str(t, digits, ARB_STR_NO_RADIUS); im_s[0] = NULL; arb_clear(t); return; } imag_zero = (qqbar_sgn_im(x) == 0); real_zero = (qqbar_sgn_re(x) == 0); /* For nonreal quadratics, getting the correct sign of the imaginary part (guaranteed by qqbar_get_acb) is sufficient. */ if (d == 2 && !imag_zero) { acb_t t; acb_init(t); digits = default_digits; qqbar_get_acb(t, x, 3.333 * digits + 10); if (real_zero) re_s[0] = NULL; else re_s[0] = arb_get_str(acb_realref(t), digits, ARB_STR_NO_RADIUS); im_s[0] = arb_get_str(acb_imagref(t), digits, ARB_STR_NO_RADIUS); acb_clear(t); return; } acb_init(z); acb_init(point); acb_init(delta); acb_poly_init(poly); arb_init(lhs); arb_init(rhs); arb_init(R); arb_init(Rpow); arb_init(tmpr); acb_set(z, QQBAR_ENCLOSURE(x)); if (imag_zero) arb_zero(acb_imagref(z)); if (real_zero) arb_zero(acb_realref(z)); re_s[0] = im_s[0] = NULL; success = 0; for (digits = default_digits; !success; digits *= 2) { prec = digits * 3.333 + 10; if (digits != 6 && 0) printf("digits %ld\n", digits); if (acb_rel_accuracy_bits(z) < prec) { _qqbar_enclosure_raw(z, QQBAR_POLY(x), z, prec); if (imag_zero) arb_zero(acb_imagref(z)); if (real_zero) arb_zero(acb_realref(z)); } flint_free(re_s[0]); flint_free(im_s[0]); re_s[0] = arb_get_str(acb_realref(z), digits, ARB_STR_NO_RADIUS); im_s[0] = arb_get_str(acb_imagref(z), digits, ARB_STR_NO_RADIUS); /* Let x be the true root and let z = a + bi be the approximate point. */ /* Verify that D(z, C*|z-x|) contains a unique root, for some C > 1. */ for (wp = prec; ; wp *= 2) { /* printf("inner loop %ld / %ld, acc %ld\n", wp, prec, acb_rel_accuracy_bits(z)); */ if (acb_rel_accuracy_bits(z) < wp) { _qqbar_enclosure_raw(z, QQBAR_POLY(x), z, wp); if (imag_zero) arb_zero(acb_imagref(z)); if (real_zero) arb_zero(acb_realref(z)); } arb_set_str(acb_realref(point), re_s[0], wp); arb_set_str(acb_imagref(point), im_s[0], wp); acb_sub(delta, z, point, wp); acb_abs(R, delta, wp); /* need more precision */ if (arb_contains_zero(R)) { success = 0; continue; } /* C = 1.25 */ arb_mul_ui(R, R, 5, wp); arb_mul_2exp_si(R, R, -2); acb_poly_set_fmpz_poly(poly, QQBAR_POLY(x), wp); acb_poly_taylor_shift(poly, poly, point, wp); /* |a_1| R > (pi/3) (|a_0| + |a_2| R^2 + ... + |a_d| R^d) */ acb_abs(lhs, poly->coeffs + 1, wp); arb_mul(lhs, lhs, R, wp); acb_abs(rhs, poly->coeffs, wp); arb_set(Rpow, R); for (k = 2; k <= d; k++) { arb_mul(Rpow, Rpow, R, wp); acb_abs(tmpr, poly->coeffs + k, wp); arb_addmul(rhs, tmpr, Rpow, wp); } arb_const_pi(tmpr, wp); arb_mul(rhs, rhs, tmpr, wp); arb_div_ui(rhs, rhs, 3, wp); if (arb_overlaps(lhs, rhs)) continue; success = arb_gt(lhs, rhs); break; } } if (real_zero) { flint_free(re_s[0]); re_s[0] = NULL; } if (imag_zero) { flint_free(im_s[0]); im_s[0] = NULL; } acb_clear(z); acb_clear(point); acb_clear(delta); acb_poly_clear(poly); arb_clear(lhs); arb_clear(rhs); arb_clear(R); arb_clear(Rpow); arb_clear(tmpr); } void qqbar_get_fexpr_root_nearest(fexpr_t res, const qqbar_t x) { char * re_s; char * im_s; qqbar_get_decimal_root_nearest(&re_s, &im_s, x, 6); _qqbar_get_fexpr_root_nearest(res, QQBAR_POLY(x), re_s, im_s); flint_free(re_s); flint_free(im_s); } void qqbar_get_fexpr_root_indexed(fexpr_t res, const qqbar_t x) { qqbar_ptr conjugates; slong d, i, j; d = qqbar_degree(x); conjugates = _qqbar_vec_init(d); qqbar_conjugates(conjugates, x); for (i = 0; i < d; i++) { if (qqbar_equal(conjugates + i, x)) { /* todo: better fexpr construction code */ fexpr_struct * coeffs; fexpr_t t, u, v; coeffs = _fexpr_vec_init(d + 1); fexpr_init(t); fexpr_init(u); fexpr_init(v); for (j = 0; j <= d; j++) fexpr_set_fmpz(coeffs + j, QQBAR_COEFFS(x) + j); fexpr_set_symbol_builtin(u, FEXPR_List); fexpr_call_vec(t, u, coeffs, d + 1); fexpr_set_si(u, i + 1); fexpr_set_symbol_builtin(v, FEXPR_PolynomialRootIndexed); fexpr_call2(res, v, t, u); _fexpr_vec_clear(coeffs, d + 1); fexpr_clear(t); fexpr_clear(u); fexpr_clear(v); break; } } _qqbar_vec_clear(conjugates, d); } void fexpr_sqrt(fexpr_t res, const fexpr_t a) { /* todo: handle aliasing in call1 */ if (res == a) { fexpr_t tmp; fexpr_init(tmp); fexpr_set(tmp, a); fexpr_sqrt(res, tmp); fexpr_clear(tmp); } else { /* todo: avoid tmp alloc */ fexpr_t tmp; fexpr_init(tmp); fexpr_set_symbol_builtin(tmp, FEXPR_Sqrt); fexpr_call1(res, tmp, a); fexpr_clear(tmp); } } void fexpr_div_ui(fexpr_t res, const fexpr_t a, ulong c) { fexpr_t t, u; fexpr_init(t); fexpr_init(u); fexpr_set_ui(u, c); fexpr_div(t, a, u); fexpr_swap(res, t); fexpr_clear(t); fexpr_clear(u); } /* cos(pi p/q) */ void _fexpr_cos_pi_pq(fexpr_t res, slong p, ulong q) { int sign = 1; int sine = 0; ulong g; fexpr_t t, u; if (p < 0) { _fexpr_cos_pi_pq(res, -p, q); return; } p = p % (2 * q); if (p > q) { p = 2 * q - p; } if (2 * p > q) { p = q - p; sign = -1; } if (p == 0) { fexpr_set_si(res, sign); return; } if (2 * p == q) { fexpr_set_ui(res, 0); return; } if (3 * p == q) { fexpr_set_si(res, sign); fexpr_div_ui(res, res, 2); return; } if (4 * p == q) { fexpr_set_ui(res, 2); fexpr_sqrt(res, res); fexpr_div_ui(res, res, 2); if (sign == -1) fexpr_neg(res, res); return; } if (6 * p == q) { fexpr_set_ui(res, 3); fexpr_sqrt(res, res); fexpr_div_ui(res, res, 2); if (sign == -1) fexpr_neg(res, res); return; } if (12 * p == q || 12 * p == 5 * q) { fexpr_init(t); fexpr_init(u); fexpr_set_ui(t, 3); fexpr_sqrt(t, t); fexpr_set_ui(u, 1); if (12 * p == q) fexpr_add(res, t, u); else fexpr_sub(res, t, u); fexpr_set_ui(t, 2); fexpr_sqrt(t, t); fexpr_mul(u, t, res); fexpr_div_ui(res, u, 4); if (sign == -1) fexpr_neg(res, res); fexpr_clear(t); fexpr_clear(u); return; } if (4 * p > q) { p = q - 2 * p; q = 2 * q; sine = 1; } g = n_gcd(p, q); if (g != 1) { p /= g; q /= g; } fexpr_init(t); fexpr_init(u); if (p == 1) { fexpr_set_symbol_builtin(res, FEXPR_Pi); } else { fexpr_set_ui(t, p); fexpr_set_symbol_builtin(u, FEXPR_Pi); fexpr_mul(res, t, u); } fexpr_div_ui(t, res, q); if (sine) fexpr_set_symbol_builtin(u, FEXPR_Sin); else fexpr_set_symbol_builtin(u, FEXPR_Cos); fexpr_call1(res, u, t); if (sign == -1) fexpr_neg(res, res); fexpr_clear(t); fexpr_clear(u); } ulong qqbar_try_as_cyclotomic(qqbar_t zeta, fmpq_poly_t poly, const qqbar_t x) { ulong * phi; ulong N1, N2, d2, order, d; slong p, q, i; double U; slong bits; int success; d = qqbar_degree(x); success = 0; order = 0; bits = 2 * qqbar_height_bits(x) /*+ 20 * d */ + 40; d2 = 4 * d; /* Compute inverse image of the totient function for d, 2*d and 4*d. */ /* Determine lower and upper bounds [N1, N2) */ U = d2; for (p = 2; p <= d2; p++) if (d2 % (p - 1) == 0 && n_is_prime(p)) U = (U * p) / (p - 1); N1 = d + 1; N2 = U + 3; /* +3 as safety for possible floating-point rounding */ /* N2 = FLINT_MIN(N2, 1 + 30); */ phi = flint_malloc(N2 * sizeof(ulong)); for (i = 0; i < N2; i++) phi[i] = i; for (p = 2; p < N2; p++) { if (phi[p] == p) { phi[p] = p - 1; for (q = 2 * p; q < N2; q += p) phi[q] = (phi[q] / p) * (p - 1); } } for (i = N1; i < N2 && !success; i++) { if (phi[i] == d || phi[i] == 2 * d || phi[i] == 4 * d) { qqbar_root_of_unity(zeta, 1, i); if (qqbar_express_in_field(poly, zeta, x, bits, 0, bits)) { order = i; success = 1; break; } } } flint_free(phi); return order; } /* poly(exp(2 pi i / n)) */ void _qqbar_get_fexpr_cyclotomic(fexpr_t res, const fmpq_poly_t poly, slong n, int pure_real, int pure_imag) { fexpr_vec_t terms; fexpr_t term, t, u, v, w; ulong p, q, g; slong i; fexpr_vec_init(terms, 0); fexpr_init(term); fexpr_init(t); fexpr_init(u); fexpr_init(v); fexpr_init(w); for (i = 0; i < poly->length; i++) { if (!fmpz_is_zero(poly->coeffs + i)) { if (i == 0) { fexpr_set_fmpz(term, poly->coeffs + i); } else { p = 2 * i; q = n; g = n_gcd(p, q); p /= g; q /= g; if (pure_real) { _fexpr_cos_pi_pq(v, p, q); } else { fexpr_set_ui(t, p); fexpr_set_symbol_builtin(u, FEXPR_Pi); fexpr_set_symbol_builtin(v, FEXPR_NumberI); fexpr_set_symbol_builtin(w, FEXPR_Mul); if (p == 1) fexpr_call2(term, w, u, v); else fexpr_call3(term, w, t, u, v); fexpr_set_ui(t, q); fexpr_div(u, term, t); fexpr_set_symbol_builtin(w, FEXPR_Exp); fexpr_call1(v, w, u); } if (fmpz_is_one(poly->coeffs + i)) fexpr_swap(term, v); else { fexpr_set_fmpz(t, poly->coeffs + i); fexpr_mul(term, t, v); } } fexpr_vec_append(terms, term); } } fexpr_set_symbol_builtin(t, FEXPR_Add); fexpr_call_vec(res, t, terms->entries, terms->length); if (!fmpz_is_one(poly->den)) { fexpr_set_fmpz(t, poly->den); fexpr_div(u, res, t); fexpr_swap(res, u); } /* todo: also want this with expanded exponentials */ if (pure_real) { fexpr_expanded_normal_form(res, res, 0); } fexpr_vec_clear(terms); fexpr_clear(term); fexpr_clear(t); fexpr_clear(u); fexpr_clear(v); fexpr_clear(w); } int qqbar_get_fexpr_formula(fexpr_t res, const qqbar_t x, ulong flags) { slong d; int success; d = qqbar_degree(x); if (d == 1) { fmpq_t r; fmpz_t t; fmpq_init(r); fmpz_init(t); qqbar_get_quadratic(fmpq_numref(r), t, t, fmpq_denref(r), x, 0); fexpr_set_fmpq(res, r); fmpq_clear(r); fmpz_clear(t); return 1; } if (d <= 2 && (flags & (QQBAR_FORMULA_QUADRATICS | QQBAR_FORMULA_GAUSSIANS))) { fmpz_t a, b, c, q; fexpr_t t, u, v; fmpz_init(a); fmpz_init(b); fmpz_init(c); fmpz_init(q); fexpr_init(t); fexpr_init(u); fexpr_init(v); qqbar_get_quadratic(a, b, c, q, x, 2); if (fmpz_equal_si(c, -1) && (flags & QQBAR_FORMULA_GAUSSIANS)) { fexpr_set_symbol_builtin(t, FEXPR_NumberI); success = 1; } else if (flags & QQBAR_FORMULA_QUADRATICS) { fexpr_set_fmpz(u, c); fexpr_set_symbol_builtin(v, FEXPR_Sqrt); fexpr_call1(t, v, u); success = 1; } else { success = 0; } if (success) { if (fmpz_is_zero(a)) { if (fmpz_equal_si(b, -1)) fexpr_neg(u, t); else if (fmpz_equal_si(b, 1)) fexpr_swap(u, t); else { fexpr_set_fmpz(v, b); fexpr_mul(u, v, t); } } else { if (fmpz_equal_si(b, -1)) { fexpr_set_fmpz(v, a); fexpr_sub(u, v, t); } else if (fmpz_equal_si(b, 1)) { fexpr_set_fmpz(v, a); fexpr_add(u, v, t); } else { fexpr_set_fmpz(u, b); fexpr_mul(v, u, t); fexpr_set_fmpz(t, a); fexpr_add(u, t, v); } } if (fmpz_is_one(q)) { fexpr_swap(res, u); } else { fexpr_set_fmpz(t, q); fexpr_div(res, u, t); } } fmpz_clear(a); fmpz_clear(b); fmpz_clear(c); fmpz_clear(q); fexpr_clear(t); fexpr_clear(u); fexpr_clear(v); if (success) return 1; } /* Identify special constants */ if (flags & QQBAR_FORMULA_CYCLOTOMICS) { slong p; ulong q; /* Quick detection of roots of unity. Todo: could also detect rational multiples of roots of unity. */ if (qqbar_is_root_of_unity(&p, &q, x)) { fexpr_t s, t, u, v, w; /* exp(2 p pi i / q) */ if (q % 2 == 0) q /= 2; else p *= 2; fexpr_init(s); fexpr_init(t); fexpr_init(u); fexpr_init(v); fexpr_init(w); fexpr_set_symbol_builtin(s, FEXPR_Mul); fexpr_set_si(t, p); fexpr_set_symbol_builtin(u, FEXPR_Pi); fexpr_set_symbol_builtin(v, FEXPR_NumberI); if (p == 1) fexpr_call2(w, s, u, v); else fexpr_call3(w, s, t, u, v); fexpr_set_si(t, q); fexpr_div(u, w, t); fexpr_set_symbol_builtin(t, FEXPR_Exp); fexpr_call1(res, t, u); fexpr_clear(s); fexpr_clear(t); fexpr_clear(u); fexpr_clear(v); fexpr_clear(w); return 1; } } /* Check for elements of cyclotomic fields */ if (flags & QQBAR_FORMULA_CYCLOTOMICS) { fmpq_poly_t poly; qqbar_t zeta; ulong q; fmpq_poly_init(poly); qqbar_init(zeta); q = qqbar_try_as_cyclotomic(zeta, poly, x); if (q != 0) _qqbar_get_fexpr_cyclotomic(res, poly, q, qqbar_sgn_im(x) == 0, qqbar_sgn_re(x) == 0); fmpq_poly_clear(poly); qqbar_clear(zeta); if (q != 0) return 1; } if (flags & QQBAR_FORMULA_DEFLATION) { slong deflation; ulong flags2; deflation = _deflation(QQBAR_COEFFS(x), d + 1); if (deflation > 1) { int neg; qqbar_t t, u, v; /* Avoid possible cases of infinite recursion. */ /* Todo: in some cases, we might want to carefully allow deflation recursively. */ flags2 = flags & ~QQBAR_FORMULA_DEFLATION; neg = qqbar_is_real(x) && qqbar_sgn_re(x) < 0; qqbar_init(t); qqbar_init(u); qqbar_init(v); if (neg) qqbar_neg(t, x); else qqbar_set(t, x); qqbar_pow_ui(u, t, deflation); success = qqbar_get_fexpr_formula(res, u, flags2); if (success) { fexpr_t a, b; fexpr_init(a); fexpr_init(b); /* todo: compute the root of unity more efficiently */ qqbar_root_ui(v, u, deflation); qqbar_div(u, x, v); if (deflation == 2) { fexpr_sqrt(b, res); } else { fexpr_set_ui(b, 1); fexpr_div_ui(a, b, deflation); fexpr_pow(b, res, a); } if (qqbar_is_one(u)) fexpr_set(res, b); else if (qqbar_is_neg_one(u)) fexpr_neg(res, b); else { /* Todo: | flags by GAUSSIANS, CYCLOTOMICS etc. to always express the root of unity? */ success = qqbar_get_fexpr_formula(a, u, flags2); if (success) fexpr_mul(res, b, a); } fexpr_clear(a); fexpr_clear(b); } qqbar_clear(t); qqbar_clear(u); qqbar_clear(v); if (success) return 1; } } /* Try a+bi or |x|*s separation. */ if ((flags & QQBAR_FORMULA_SEPARATION) && !qqbar_is_real(x)) { qqbar_t a, b; fexpr_t t, u, v; ulong flags2; qqbar_init(a); qqbar_init(b); fexpr_init(t); fexpr_init(u); fexpr_init(v); qqbar_re_im(a, b, x); /* Avoid possible cases of infinite recursion. */ /* Todo: in some cases, we might want to carefully allow separation recursively, e.g. if the degree has been strictly decreased. */ flags2 = flags & ~QQBAR_FORMULA_SEPARATION; success = (qqbar_degree(a) <= d) && (qqbar_degree(b) <= d) && qqbar_get_fexpr_formula(t, a, flags2) && qqbar_get_fexpr_formula(u, b, flags2); if (success) { fexpr_set_symbol_builtin(res, FEXPR_NumberI); fexpr_mul(v, u, res); if (qqbar_is_zero(a)) fexpr_swap(res, v); else fexpr_add(res, t, v); } else { qqbar_abs(a, x); if (qqbar_degree(a) <= d && qqbar_get_fexpr_formula(t, a, flags2)) { qqbar_div(b, x, a); if (qqbar_get_fexpr_formula(u, b, flags2)) { fexpr_mul(res, t, u); success = 1; } } } qqbar_clear(a); qqbar_clear(b); fexpr_clear(t); fexpr_clear(u); fexpr_clear(v); if (success) return 1; } return 0; } calcium-0.4.1/qqbar/get_fmpq.c000066400000000000000000000014331407704557200162210ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void _qqbar_get_fmpq(fmpz_t num, fmpz_t den, const qqbar_t x) { if (qqbar_degree(x) != 1) { flint_printf("_qqbar_get_fmpq: not a rational value\n"); flint_abort(); } fmpz_neg(num, QQBAR_COEFFS(x)); fmpz_set(den, QQBAR_COEFFS(x) + 1); } void qqbar_get_fmpq(fmpq_t res, const qqbar_t x) { _qqbar_get_fmpq(fmpq_numref(res), fmpq_denref(res), x); } calcium-0.4.1/qqbar/get_fmpz.c000066400000000000000000000012221407704557200162260ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_get_fmpz(fmpz_t res, const qqbar_t x) { if (qqbar_degree(x) != 1 || !fmpz_is_one(QQBAR_COEFFS(x) + 1)) { flint_printf("qqbar_get_fmpz: not an integer\n"); flint_abort(); } fmpz_neg(res, QQBAR_COEFFS(x)); } calcium-0.4.1/qqbar/get_quadratic.c000066400000000000000000000125401407704557200172340ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" /* Write |n| = A * B^2 factoring = 0 -> no factoring except for powers of two factoring = 1 -> complete factoring factoring = 2 -> smooth factoring */ static void _fmpz_factor_square_root(fmpz_t A, fmpz_t B, const fmpz_t n, int factoring) { if (factoring == 0) { slong v; v = fmpz_val2(n); fmpz_abs(A, n); fmpz_one(B); if (v >= 2) { fmpz_tdiv_q_2exp(A, A, v - (v & 1)); fmpz_mul_2exp(B, B, v / 2); } } else { fmpz_factor_t fac; fmpz_t t; slong i; fmpz_factor_init(fac); if (factoring == 1) fmpz_factor(fac, n); else fmpz_factor_smooth(fac, n, 32, -1); /* 32 bit factors, -1 => no primality test */ fmpz_one(A); fmpz_one(B); fmpz_init(t); for (i = 0; i < fac->num; i++) { if (fac->exp[i] == 1) { fmpz_mul(A, A, fac->p + i); } else if (fac->exp[i] == 2) { fmpz_mul(B, B, fac->p + i); } else { fmpz_pow_ui(t, fac->p + i, fac->exp[i] / 2); fmpz_mul(B, B, t); if (fac->exp[i] % 2) fmpz_mul(A, A, fac->p + i); } } fmpz_factor_clear(fac); fmpz_clear(t); } } void qqbar_get_quadratic(fmpz_t res_a, fmpz_t res_b, fmpz_t res_c, fmpz_t res_q, const qqbar_t x, int factoring) { const fmpz *a, *b, *c; fmpz_t D; if (qqbar_degree(x) == 1) { fmpz_zero(res_b); fmpz_zero(res_c); _qqbar_get_fmpq(res_a, res_q, x); return; } if (qqbar_degree(x) != 2) { flint_printf("qqbar_get_quadratic: degree 1 or 2 is required\n"); flint_abort(); } a = QQBAR_COEFFS(x) + 2; b = QQBAR_COEFFS(x) + 1; c = QQBAR_COEFFS(x) + 0; /* x = (-b +/- sqrt(b^2 - 4ac))/(2a) */ fmpz_init(D); fmpz_mul(D, a, c); fmpz_mul_2exp(D, D, 2); fmpz_submul(D, b, b); /* -D is a square <=> element of Q(i) */ if (fmpz_is_square(D)) { fmpz_sqrt(D, D); fmpz_set_si(res_c, -1); if (qqbar_sgn_im(x) > 0) fmpz_set(res_b, D); else fmpz_neg(res_b, D); fmpz_neg(res_a, b); fmpz_mul_2exp(res_q, a, 1); fmpz_gcd(D, res_a, res_b); fmpz_gcd(D, D, res_q); if (!fmpz_is_one(D)) { fmpz_divexact(res_a, res_a, D); fmpz_divexact(res_b, res_b, D); fmpz_divexact(res_q, res_q, D); } } else { fmpz_t A, B; fmpz_neg(D, D); fmpz_init(A); fmpz_init(B); /* sqrt(|D|) = A * B^2 => sqrt(D) = sqrt(A) * B (D > 0) sqrt(-A) * B (D < 0) */ _fmpz_factor_square_root(A, B, D, factoring); if (fmpz_sgn(D) < 0) fmpz_neg(A, A); fmpz_set(res_c, A); /* x = (-b +/- B*sqrt(A))/(2a) */ fmpz_neg(res_a, b); fmpz_mul_2exp(res_q, a, 1); /* determine the correct sign */ if (fmpz_sgn(D) < 0) { if (qqbar_sgn_im(x) > 0) fmpz_set(res_b, B); else fmpz_neg(res_b, B); } else if (fmpz_is_zero(b)) { if (qqbar_sgn_re(x) > 0) fmpz_set(res_b, B); else fmpz_neg(res_b, B); } else { arb_t r1, r2; slong prec; arb_init(r1); arb_init(r2); for (prec = 64; ; prec *= 2) { arb_sqrt_fmpz(r1, A, prec); arb_mul_fmpz(r1, r1, B, prec); arb_add_fmpz(r2, r1, b, prec); arb_neg(r2, r2); arb_sub_fmpz(r1, r1, b, prec); arb_div_fmpz(r1, r1, a, prec); arb_div_fmpz(r2, r2, a, prec); arb_mul_2exp_si(r1, r1, -1); arb_mul_2exp_si(r2, r2, -1); if (arb_overlaps(r1, acb_realref(QQBAR_ENCLOSURE(x))) && !arb_overlaps(r2, acb_realref(QQBAR_ENCLOSURE(x)))) { fmpz_set(res_b, B); break; } if (arb_overlaps(r2, acb_realref(QQBAR_ENCLOSURE(x))) && !arb_overlaps(r1, acb_realref(QQBAR_ENCLOSURE(x)))) { fmpz_neg(res_b, B); break; } } arb_clear(r1); arb_clear(r2); } fmpz_gcd(D, res_a, res_b); fmpz_gcd(D, D, res_q); if (!fmpz_is_one(D)) { fmpz_divexact(res_a, res_a, D); fmpz_divexact(res_b, res_b, D); fmpz_divexact(res_q, res_q, D); } fmpz_clear(A); fmpz_clear(B); } fmpz_clear(D); } calcium-0.4.1/qqbar/guess.c000066400000000000000000000071561407704557200155550ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "flint/fmpz_lll.h" #include "arb_fmpz_poly.h" #include "qqbar.h" #define QQBAR_GUESS_TRY_SMALLER 1 #define QQBAR_GUESS_CHECK 2 int qqbar_guess(qqbar_t res, const acb_t z, slong max_deg, slong max_bits, int flags, slong prec) { acb_ptr zpow; int found; slong i, j, fac_bits, prec2; fmpz_poly_t poly; fmpz_poly_factor_t fac; acb_t z2; mag_t rad; if (!acb_is_finite(z)) return 0; if (max_deg > 8 && (flags & QQBAR_GUESS_TRY_SMALLER)) { if (qqbar_guess(res, z, max_deg / 4, max_bits, flags, prec)) return 1; } found = 0; fmpz_poly_init2(poly, max_deg + 1); fmpz_poly_factor_init(fac); acb_init(z2); mag_init(rad); zpow = _acb_vec_init(max_deg + 1); _acb_vec_set_powers(zpow, z, max_deg + 1, prec); _fmpz_poly_set_length(poly, max_deg + 1); if (_qqbar_acb_lindep(poly->coeffs, zpow, max_deg + 1, 1, prec)) { _fmpz_poly_normalise(poly); fmpz_poly_factor(fac, poly); for (i = 0; i < fac->num; i++) { fac_bits = fmpz_poly_max_bits(fac->p + i); fac_bits = FLINT_ABS(fac_bits); if (fac_bits <= max_bits) { slong deg; qqbar_ptr roots; /* Rule out p(x) != 0 */ arb_fmpz_poly_evaluate_acb(z2, fac->p + i, z, prec); if (acb_contains_zero(z2)) { /* Try to use the original interval, to avoid computing the polynomial roots... */ if (acb_rel_accuracy_bits(z) >= QQBAR_DEFAULT_PREC - 3) { for (prec2 = QQBAR_DEFAULT_PREC / 2; prec2 < 2 * prec; prec2 *= 2) { acb_set(z2, z); acb_get_mag(rad, z); mag_mul_2exp_si(rad, rad, -prec2); acb_add_error_mag(z2, rad); if (_qqbar_validate_existence_uniqueness(z2, fac->p + i, z2, 2 * prec2)) { fmpz_poly_set(QQBAR_POLY(res), fac->p + i); acb_set(QQBAR_ENCLOSURE(res), z2); found = 1; break; } } } deg = fmpz_poly_degree(fac->p + i); roots = _qqbar_vec_init(deg); qqbar_roots_fmpz_poly(roots, fac->p + i, QQBAR_ROOTS_IRREDUCIBLE); for (j = 0; j < deg; j++) { qqbar_get_acb(z2, roots + j, prec); if (acb_overlaps(z, z2)) { qqbar_swap(res, roots + j); found = 1; break; } } _qqbar_vec_clear(roots, deg); if (found) break; } } } } fmpz_poly_clear(poly); fmpz_poly_factor_clear(fac); _acb_vec_clear(zpow, max_deg + 1); acb_clear(z2); mag_clear(rad); return found; } calcium-0.4.1/qqbar/hash.c000066400000000000000000000014101407704557200153350ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" ulong qqbar_hash(const qqbar_t x) { ulong s; slong i, len; const fmpz * c; len = QQBAR_POLY(x)->length; c = QQBAR_COEFFS(x); s = 1234567; for (i = 0; i < len; i++) s = calcium_fmpz_hash(c + i) * 1000003 + s; /* todo: add in some bits describing the enclosure, e.g. a floor value or just the signs */ return s; } calcium-0.4.1/qqbar/height.c000066400000000000000000000007651407704557200156760ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_height(fmpz_t res, const qqbar_t x) { fmpz_poly_height(res, QQBAR_POLY(x)); } calcium-0.4.1/qqbar/height_bits.c000066400000000000000000000010401407704557200167020ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" slong qqbar_height_bits(const qqbar_t x) { slong bits; bits = fmpz_poly_max_bits(QQBAR_POLY(x)); return FLINT_ABS(bits); } calcium-0.4.1/qqbar/i.c000066400000000000000000000011461407704557200146500ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_i(qqbar_t res) { fmpz_poly_zero(QQBAR_POLY(res)); fmpz_poly_set_coeff_si(QQBAR_POLY(res), 2, 1); fmpz_poly_set_coeff_si(QQBAR_POLY(res), 0, 1); acb_onei(QQBAR_ENCLOSURE(res)); } calcium-0.4.1/qqbar/im.c000066400000000000000000000020251407704557200150220ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_im(qqbar_t res, const qqbar_t x) { if (qqbar_sgn_im(x) == 0) { qqbar_zero(res); } else { qqbar_t t; qqbar_init(t); if (qqbar_sgn_re(x) == 0) { qqbar_i(t); qqbar_mul(res, x, t); qqbar_neg(res, res); } else { qqbar_conj(t, x); qqbar_sub(res, x, t); qqbar_i(t); qqbar_mul(res, res, t); qqbar_neg(res, res); qqbar_mul_2exp_si(res, res, -1); } arb_zero(acb_imagref(QQBAR_ENCLOSURE(res))); qqbar_clear(t); } } calcium-0.4.1/qqbar/init.c000066400000000000000000000010661407704557200153640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_init(qqbar_t res) { fmpz_poly_init(QQBAR_POLY(res)); fmpz_poly_set_coeff_si(QQBAR_POLY(res), 1, 1); acb_init(QQBAR_ENCLOSURE(res)); } calcium-0.4.1/qqbar/inlines.c000066400000000000000000000006601407704557200160610ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #define QQBAR_INLINES_C #include "qqbar.h" calcium-0.4.1/qqbar/inv.c000066400000000000000000000037541407704557200152230ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "arb_fmpz_poly.h" #include "qqbar.h" void qqbar_inv(qqbar_t res, const qqbar_t x) { slong d; if (qqbar_is_zero(x)) { flint_printf("qqbar_inv: division by zero\n"); flint_abort(); } if (qqbar_is_one(x) || qqbar_is_neg_one(x)) { qqbar_set(res, x); return; } d = qqbar_degree(x); if (d == 1) { fmpz_poly_reverse(QQBAR_POLY(res), QQBAR_POLY(x), d + 1); if (fmpz_sgn(QQBAR_COEFFS(res) + d) < 0) fmpz_poly_neg(QQBAR_POLY(res), QQBAR_POLY(res)); arb_fmpz_div_fmpz(acb_realref(QQBAR_ENCLOSURE(res)), QQBAR_COEFFS(res), QQBAR_COEFFS(res) + 1, QQBAR_DEFAULT_PREC); arb_neg(acb_realref(QQBAR_ENCLOSURE(res)), acb_realref(QQBAR_ENCLOSURE(res))); arb_zero(acb_imagref(QQBAR_ENCLOSURE(res))); } else { fmpz_poly_t pol; slong prec; acb_t z, t; fmpz_poly_init(pol); acb_init(z); acb_init(t); fmpz_poly_reverse(pol, QQBAR_POLY(x), d + 1); if (fmpz_sgn(pol->coeffs + d) < 0) fmpz_poly_neg(pol, pol); acb_set(z, QQBAR_ENCLOSURE(x)); for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { _qqbar_enclosure_raw(z, QQBAR_POLY(x), z, prec); acb_inv(t, z, prec); if (_qqbar_validate_uniqueness(t, pol, t, 2 * prec)) { fmpz_poly_set(QQBAR_POLY(res), pol); acb_set(QQBAR_ENCLOSURE(res), t); break; } } fmpz_poly_clear(pol); acb_clear(z); acb_clear(t); } } calcium-0.4.1/qqbar/log_pi_i.c000066400000000000000000000013131407704557200161750ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_log_pi_i(slong * p, ulong * q, const qqbar_t x) { int ok; ok = qqbar_is_root_of_unity(p, q, x); if (ok) { if (*q % 2 == 0) *q /= 2; else *p *= 2; while (*p > (slong) *q) *p -= 2 * (slong) (*q); } return ok; } calcium-0.4.1/qqbar/mul.c000066400000000000000000000061741407704557200152230ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_mul(qqbar_t res, const qqbar_t x, const qqbar_t y) { if (qqbar_is_zero(x) || qqbar_is_zero(y)) { qqbar_zero(res); } else if (qqbar_is_one(x)) { qqbar_set(res, y); } else if (qqbar_is_one(y)) { qqbar_set(res, x); } else if (qqbar_is_neg_one(x)) { qqbar_neg(res, y); } else if (qqbar_is_neg_one(y)) { qqbar_neg(res, x); } else if (qqbar_is_rational(y)) { fmpz_t a, b, c; fmpz_init(a); fmpz_init(b); fmpz_init(c); _qqbar_get_fmpq(a, c, y); qqbar_scalar_op(res, x, a, b, c); fmpz_clear(a); fmpz_clear(b); fmpz_clear(c); } else if (qqbar_is_rational(x)) { fmpz_t a, b, c; fmpz_init(a); fmpz_init(b); fmpz_init(c); _qqbar_get_fmpq(a, c, x); qqbar_scalar_op(res, y, a, b, c); fmpz_clear(a); fmpz_clear(b); fmpz_clear(c); } else if (qqbar_equal(x, y)) { /* This may detect exact square roots and other special cases. */ qqbar_pow_ui(res, x, 2); } else if (_qqbar_fast_detect_simple_principal_surd(x) && _qqbar_fast_detect_simple_principal_surd(y)) { /* (p/q)^(1/d) * (r/s)^(1/e) */ fmpq_t t, u; ulong d, e, f, g; d = qqbar_degree(x); e = qqbar_degree(y); g = n_gcd(d, e); f = (d / g) * e; fmpq_init(t); fmpq_init(u); fmpz_neg(fmpq_numref(t), QQBAR_COEFFS(x)); fmpz_set(fmpq_denref(t), QQBAR_COEFFS(x) + d); fmpz_neg(fmpq_numref(u), QQBAR_COEFFS(y)); fmpz_set(fmpq_denref(u), QQBAR_COEFFS(y) + e); fmpq_pow_si(t, t, e / g); fmpq_pow_si(u, u, d / g); fmpq_mul(t, t, u); /* todo: recycle the existing enclosures instead of computing a numerical f-th root from scratch */ qqbar_fmpq_root_ui(res, t, f); fmpq_clear(t); fmpq_clear(u); } else { qqbar_binary_op(res, x, y, 2); } } void qqbar_mul_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpq(t, y); qqbar_mul(res, x, t); qqbar_clear(t); } void qqbar_mul_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpz(t, y); qqbar_mul(res, x, t); qqbar_clear(t); } void qqbar_mul_ui(qqbar_t res, const qqbar_t x, ulong y) { qqbar_t t; qqbar_init(t); qqbar_set_ui(t, y); qqbar_mul(res, x, t); qqbar_clear(t); } void qqbar_mul_si(qqbar_t res, const qqbar_t x, slong y) { qqbar_t t; qqbar_init(t); qqbar_set_si(t, y); qqbar_mul(res, x, t); qqbar_clear(t); } calcium-0.4.1/qqbar/mul_2exp_si.c000066400000000000000000000030501407704557200166420ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_mul_2exp_si(qqbar_t res, const qqbar_t x, slong exp) { slong i, d, g, h; fmpz * coeffs; d = qqbar_degree(x); if (qqbar_is_zero(x) || exp == 0) { qqbar_set(res, x); return; } if (FLINT_BIT_COUNT(d) + FLINT_BIT_COUNT((ulong) FLINT_ABS(exp)) > FLINT_BITS - 8) { flint_printf("qqbar_mul_2exp_si: ludicrously large coefficients\n"); flint_abort(); } fmpz_poly_set(QQBAR_POLY(res), QQBAR_POLY(x)); acb_mul_2exp_si(QQBAR_ENCLOSURE(res), QQBAR_ENCLOSURE(x), exp); coeffs = QQBAR_COEFFS(res); /* todo: compute valuations in advance */ if (exp >= 0) { for (i = 1; i <= d; i++) fmpz_mul_2exp(coeffs + d - i, coeffs + d - i, i * exp); } else { for (i = 1; i <= d; i++) fmpz_mul_2exp(coeffs + i, coeffs + i, i * (-exp)); } g = fmpz_val2(coeffs); for (i = 1; i <= d; i++) { if (!fmpz_is_zero(coeffs + i)) { h = fmpz_val2(coeffs + i); g = FLINT_MIN(g, h); } } if (g != 0) fmpz_poly_scalar_tdiv_2exp(QQBAR_POLY(res), QQBAR_POLY(res), g); } calcium-0.4.1/qqbar/neg.c000066400000000000000000000013071407704557200151700ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_neg(qqbar_t res, const qqbar_t x) { slong i; fmpz_poly_set(QQBAR_POLY(res), QQBAR_POLY(x)); for (i = fmpz_poly_degree(QQBAR_POLY(res)) - 1; i >= 0; i -= 2) fmpz_neg(QQBAR_COEFFS(res) + i, QQBAR_COEFFS(res) + i); acb_neg(QQBAR_ENCLOSURE(res), QQBAR_ENCLOSURE(x)); } calcium-0.4.1/qqbar/numerator.c000066400000000000000000000012661407704557200164370ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_numerator(qqbar_t res, const qqbar_t y) { if (qqbar_is_algebraic_integer(y)) { qqbar_set(res, y); } else { fmpz_t t; fmpz_init(t); qqbar_denominator(t, y); qqbar_mul_fmpz(res, y, t); fmpz_clear(t); } } calcium-0.4.1/qqbar/phi.c000066400000000000000000000017021407704557200151760ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_phi(qqbar_t res) { fmpz_poly_zero(QQBAR_POLY(res)); fmpz_poly_set_coeff_si(QQBAR_POLY(res), 2, 1); fmpz_poly_set_coeff_si(QQBAR_POLY(res), 1, -1); fmpz_poly_set_coeff_si(QQBAR_POLY(res), 0, -1); arb_sqrt_ui(acb_realref(QQBAR_ENCLOSURE(res)), 5, QQBAR_DEFAULT_PREC); arb_add_ui(acb_realref(QQBAR_ENCLOSURE(res)), acb_realref(QQBAR_ENCLOSURE(res)), 1, QQBAR_DEFAULT_PREC); arb_mul_2exp_si(acb_realref(QQBAR_ENCLOSURE(res)), acb_realref(QQBAR_ENCLOSURE(res)), -1); arb_zero(acb_imagref(QQBAR_ENCLOSURE(res))); } calcium-0.4.1/qqbar/pow.c000066400000000000000000000175121407704557200152310ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "flint/fmpz_poly_factor.h" #include "arb_fmpz_poly.h" #include "qqbar.h" void _qqbar_sqr_undeflatable(qqbar_t res, const qqbar_t x) { fmpz_poly_t A, B; acb_t z, t, w; slong i, prec, d; int pure_real, pure_imag; fmpz_poly_init(A); fmpz_poly_init(B); acb_init(z); acb_init(t); acb_init(w); d = fmpz_poly_degree(QQBAR_POLY(x)); for (i = 0; i <= d; i++) { if (i % 2 == 0) fmpz_poly_set_coeff_fmpz(A, i / 2, QQBAR_POLY(x)->coeffs + i); else fmpz_poly_set_coeff_fmpz(B, i / 2, QQBAR_POLY(x)->coeffs + i); } fmpz_poly_sqr(A, A); fmpz_poly_sqr(B, B); fmpz_poly_shift_left(B, B, 1); fmpz_poly_sub(A, A, B); if (fmpz_sgn(A->coeffs + A->length - 1) < 0) fmpz_poly_neg(A, A); acb_set(z, QQBAR_ENCLOSURE(x)); pure_real = (qqbar_sgn_im(x) == 0); pure_imag = (qqbar_sgn_re(x) == 0); for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { _qqbar_enclosure_raw(z, QQBAR_POLY(x), z, prec); if (pure_real) arb_zero(acb_imagref(z)); if (pure_imag) arb_zero(acb_realref(z)); acb_sqr(w, z, prec); if (_qqbar_validate_uniqueness(t, A, w, 2 * prec)) { fmpz_poly_set(QQBAR_POLY(res), A); acb_set(QQBAR_ENCLOSURE(res), t); break; } } fmpz_poly_clear(A); fmpz_poly_clear(B); acb_clear(z); acb_clear(t); acb_clear(w); } /* todo: use number field arithmetic, other optimisations ... */ void qqbar_pow_ui(qqbar_t res, const qqbar_t x, ulong n) { if (n == 0) { qqbar_one(res); } else if (n == 1) { qqbar_set(res, x); } else if (qqbar_is_rational(x)) { fmpq_t t; fmpq_init(t); qqbar_get_fmpq(t, x); fmpz_pow_ui(fmpq_numref(t), fmpq_numref(t), n); fmpz_pow_ui(fmpq_denref(t), fmpq_denref(t), n); qqbar_set_fmpq(res, t); fmpq_clear(t); } else { slong p; ulong q; ulong f; /* Fast path for roots of unity. Todo: generalize to rational multiples of roots of unity. */ if (qqbar_is_root_of_unity(&p, &q, x)) { if (p < 0) p += 2 * q; p = n_mulmod2(p, n, 2 * q); qqbar_root_of_unity(res, p, q); return; } /* Fast detection of perfect powers */ f = arb_fmpz_poly_deflation(QQBAR_POLY(x)); if (f % n == 0) { acb_t z, t, w; fmpz_poly_t H; slong prec; int pure_real, pure_imag; fmpz_poly_init(H); acb_init(z); acb_init(t); acb_init(w); arb_fmpz_poly_deflate(H, QQBAR_POLY(x), n); acb_set(z, QQBAR_ENCLOSURE(x)); pure_real = (qqbar_sgn_im(x) == 0); pure_imag = (qqbar_sgn_re(x) == 0); for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { _qqbar_enclosure_raw(z, QQBAR_POLY(x), z, prec); if (pure_real) arb_zero(acb_imagref(z)); if (pure_imag) arb_zero(acb_realref(z)); acb_pow_ui(w, z, n, prec); if (_qqbar_validate_uniqueness(t, H, w, 2 * prec)) { fmpz_poly_set(QQBAR_POLY(res), H); acb_set(QQBAR_ENCLOSURE(res), t); break; } } fmpz_poly_clear(H); acb_clear(z); acb_clear(t); acb_clear(w); return; } /* fast path for principal roots of positive rational numbers */ if (_qqbar_fast_detect_simple_principal_surd(x)) { fmpq_t t; fmpq_init(t); fmpz_neg(fmpq_numref(t), QQBAR_COEFFS(x)); fmpz_set(fmpq_denref(t), QQBAR_COEFFS(x) + qqbar_degree(x)); fmpq_pow_si(t, t, n); qqbar_fmpq_root_ui(res, t, qqbar_degree(x)); fmpq_clear(t); return; } if (n == 2) { _qqbar_sqr_undeflatable(res, x); } else { /* todo: don't construct this polynomial when n is huge */ fmpz * coeffs; fmpz_t den; coeffs = _fmpz_vec_init(n + 1); fmpz_one(coeffs + n); *den = 1; _qqbar_evaluate_fmpq_poly(res, coeffs, den, n + 1, x); _fmpz_vec_clear(coeffs, n + 1); } } } void qqbar_pow_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y) { if (fmpq_is_zero(y)) { qqbar_one(res); } else if (fmpq_is_one(y)) { qqbar_set(res, x); } else if (qqbar_is_one(x)) { qqbar_one(res); } else if (qqbar_is_zero(x)) { if (fmpq_sgn(y) <= 0) { flint_printf("qqbar_pow_fmpq: division by zero\n"); flint_abort(); } qqbar_zero(res); } else { fmpq_t t; fmpz_t r; slong p; ulong q; fmpq_init(t); fmpz_init(r); fmpq_set(t, y); /* Fast path for roots of unity. */ if (qqbar_is_root_of_unity(&p, &q, x)) { fmpz_mul_si(fmpq_numref(t), fmpq_numref(t), p); fmpz_mul_ui(fmpq_denref(t), fmpq_denref(t), q); fmpz_mul_ui(r, fmpq_denref(t), 2); fmpz_fdiv_r(fmpq_numref(t), fmpq_numref(t), r); fmpq_canonicalise(t); if (COEFF_IS_MPZ(*fmpq_denref(t))) { flint_printf("qqbar_pow: excessive exponent\n"); flint_abort(); } qqbar_root_of_unity(res, *fmpq_numref(t), *fmpq_denref(t)); } else { if (COEFF_IS_MPZ(*fmpq_numref(t)) || COEFF_IS_MPZ(*fmpq_denref(t))) { flint_printf("qqbar_pow: excessive exponent\n"); flint_abort(); } p = *fmpq_numref(t); q = *fmpq_denref(t); qqbar_root_ui(res, x, q); if (p >= 0) qqbar_pow_ui(res, res, p); else { qqbar_pow_ui(res, res, -p); qqbar_inv(res, res); } } fmpq_clear(t); fmpz_clear(r); } } void qqbar_pow_si(qqbar_t res, const qqbar_t x, slong n) { if (n >= 0) { qqbar_pow_ui(res, x, n); } else { fmpq_t t; fmpq_init(t); fmpz_set_si(fmpq_numref(t), n); qqbar_pow_fmpq(res, x, t); fmpq_clear(t); } } void qqbar_pow_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t n) { fmpq_t t; fmpq_init(t); fmpz_set(fmpq_numref(t), n); qqbar_pow_fmpq(res, x, t); fmpq_clear(t); } int qqbar_pow(qqbar_t res, const qqbar_t x, const qqbar_t y) { if (qqbar_is_zero(y)) { qqbar_one(res); return 1; } else if (qqbar_is_one(y)) { qqbar_set(res, x); return 1; } else if (qqbar_is_one(x)) { qqbar_one(res); return 1; } else if (qqbar_is_zero(x)) { if (qqbar_sgn_re(y) <= 0) return 0; qqbar_zero(res); return 1; } else if (qqbar_is_rational(y)) { fmpq_t t; fmpq_init(t); qqbar_get_fmpq(t, y); qqbar_pow_fmpq(res, x, t); fmpq_clear(t); return 1; } else { return 0; } } calcium-0.4.1/qqbar/print.c000066400000000000000000000015071407704557200155550ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_print(const qqbar_t x) { slong i, d; d = qqbar_degree(x); flint_printf("deg %wd [", qqbar_degree(x)); for (i = 0; i <= d; i++) { fmpz_print(QQBAR_COEFFS(x) + i); if (i < d) flint_printf(", "); } flint_printf("] "); acb_printn(QQBAR_ENCLOSURE(x), FLINT_MAX(6, FLINT_MIN(acb_rel_accuracy_bits(QQBAR_ENCLOSURE(x)), acb_bits(QQBAR_ENCLOSURE(x)))), 0); } calcium-0.4.1/qqbar/printn.c000066400000000000000000000014031407704557200157260ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_printn(const qqbar_t x, slong n) { acb_t t; slong prec; n = FLINT_MAX(1, n); prec = n * 3.333 + 10; acb_init(t); qqbar_get_acb(t, x, prec); acb_printn(t, n, ARB_STR_NO_RADIUS); acb_clear(t); } void qqbar_printnd(const qqbar_t x, slong n) { qqbar_printn(x, n); flint_printf(" (deg %wd)", qqbar_degree(x)); } calcium-0.4.1/qqbar/randtest.c000066400000000000000000000123621407704557200162460ustar00rootroot00000000000000/* Copyright (C) 2016 Vincent Delecroix Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "flint/fmpz_mod_poly.h" #include "flint/fmpz_poly_factor.h" #include "arb_fmpz_poly.h" #include "qqbar.h" #if __FLINT_RELEASE >= 20700 static void fmpz_poly_randtest_irreducible1(fmpz_poly_t p, flint_rand_t state, slong len, mp_bitcnt_t bits) { slong i; fmpz_t c; fmpz_mod_ctx_t ctx; fmpz_mod_poly_t q; len = 1 + n_randint(state, len); fmpz_init(c); if (bits == 1) fmpz_set_ui(c, 2); else fmpz_randprime(c, state, bits, 0); fmpz_mod_ctx_init(ctx, c); fmpz_mod_poly_init(q, ctx); fmpz_mod_poly_randtest_irreducible(q, state, len, ctx); fmpz_mod_poly_get_fmpz_poly(p, q, ctx); /* After lifting, the coefficients belong to {0, ..., c-1}. We now */ /* randomly subtract c so that some of them become negative. */ for (i = 0; i < p->length; i++) { if (n_randint(state, 3) == 0 && !(bits == 1 && fmpz_is_zero(p->coeffs + i))) fmpz_sub(p->coeffs + i, p->coeffs + i, c); } fmpz_poly_content(c, p); fmpz_poly_scalar_divexact_fmpz(p, p, c); fmpz_mod_poly_clear(q, ctx); fmpz_mod_ctx_clear(ctx); fmpz_clear(c); } #else static void fmpz_poly_randtest_irreducible1(fmpz_poly_t p, flint_rand_t state, slong len, mp_bitcnt_t bits) { slong i; fmpz_t c; fmpz_mod_poly_t q; len = 1 + n_randint(state, len); fmpz_init(c); if (bits == 1) fmpz_set_ui(c, 2); else fmpz_randprime(c, state, bits, 0); fmpz_mod_poly_init(q, c); fmpz_mod_poly_randtest_irreducible(q, state, len); fmpz_mod_poly_get_fmpz_poly(p, q); /* After lifting, the coefficients belong to {0, ..., c-1}. We now */ /* randomly subtract c so that some of them become negative. */ for (i = 0; i < p->length; i++) { if (n_randint(state, 3) == 0 && !(bits == 1 && fmpz_is_zero(p->coeffs + i))) fmpz_sub(p->coeffs + i, p->coeffs + i, c); } fmpz_poly_content(c, p); fmpz_poly_scalar_divexact_fmpz(p, p, c); fmpz_mod_poly_clear(q); fmpz_clear(c); } #endif static void fmpz_poly_randtest_irreducible2(fmpz_poly_t pol, flint_rand_t state, slong len, mp_bitcnt_t bits) { while (1) { slong i; fmpz_poly_factor_t fac; do { fmpz_poly_randtest(pol, state, len, bits); } while (fmpz_poly_degree(pol) < 1); fmpz_poly_factor_init(fac); fmpz_poly_factor(fac, pol); i = n_randint(state, fac->num); if (FLINT_ABS(fmpz_poly_max_bits(fac->p + i)) <= bits) { fmpz_poly_set(pol, fac->p + i); fmpz_poly_factor_clear(fac); break; } fmpz_poly_factor_clear(fac); } } void _qqbar_randtest(qqbar_t res, flint_rand_t state, slong deg, slong bits, int real) { fmpz_poly_t pol; slong prec, i, rdeg, r1, r2; acb_ptr roots; deg = FLINT_MAX(deg, 1); bits = FLINT_MAX(bits, 1); if ((deg == 1 || n_randint(state, 4) == 0) && real != 2) { fmpq_t t; fmpq_init(t); do { fmpq_randtest(t, state, bits); } while (fmpz_bits(fmpq_numref(t)) > bits || fmpz_bits(fmpq_denref(t)) > bits); qqbar_set_fmpq(res, t); fmpq_clear(t); return; } fmpz_poly_init(pol); do { if (n_randint(state, 2)) fmpz_poly_randtest_irreducible1(pol, state, deg + 1, bits); else fmpz_poly_randtest_irreducible2(pol, state, deg + 1, bits); rdeg = fmpz_poly_degree(pol); r1 = rdeg; r2 = 0; if (real) fmpz_poly_signature(&r1, &r2, pol); } while (rdeg < 1 || (real == 1 && r1 < 1) || (real == 2 && r2 < 1)); if (fmpz_sgn(pol->coeffs + rdeg) < 0) fmpz_poly_neg(pol, pol); roots = _acb_vec_init(rdeg); if (real == 0) i = n_randint(state, rdeg); else if (real == 1) i = n_randint(state, r1); else i = r1 + n_randint(state, 2 * r2); for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { arb_fmpz_poly_complex_roots(roots, pol, 0, prec); if (_qqbar_validate_uniqueness(roots + i, pol, roots + i, 2 * prec)) { fmpz_poly_set(QQBAR_POLY(res), pol); acb_set(QQBAR_ENCLOSURE(res), roots + i); break; } } _acb_vec_clear(roots, rdeg); fmpz_poly_clear(pol); } void qqbar_randtest(qqbar_t res, flint_rand_t state, slong deg, slong bits) { _qqbar_randtest(res, state, deg, bits, 0); } void qqbar_randtest_real(qqbar_t res, flint_rand_t state, slong deg, slong bits) { _qqbar_randtest(res, state, deg, bits, 1); } void qqbar_randtest_nonreal(qqbar_t res, flint_rand_t state, slong deg, slong bits) { if (deg <= 1) { flint_printf("qqbar_randtest_nonreal: must have deg >= 2\n"); flint_abort(); } _qqbar_randtest(res, state, deg, bits, 2); } calcium-0.4.1/qqbar/re.c000066400000000000000000000015021407704557200150220ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_re(qqbar_t res, const qqbar_t x) { if (qqbar_sgn_im(x) == 0) { qqbar_set(res, x); } else if (qqbar_sgn_re(x) == 0) { qqbar_zero(res); } else { qqbar_t t; qqbar_init(t); qqbar_conj(t, x); qqbar_add(res, x, t); arb_zero(acb_imagref(QQBAR_ENCLOSURE(res))); qqbar_mul_2exp_si(res, res, -1); qqbar_clear(t); } } calcium-0.4.1/qqbar/re_im.c000066400000000000000000000011721407704557200155120ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_re_im(qqbar_t res1, qqbar_t res2, const qqbar_t x) { if (res1 == x) { qqbar_im(res2, x); qqbar_re(res1, x); } else { qqbar_re(res1, x); qqbar_im(res2, x); } } calcium-0.4.1/qqbar/root_of_unity.c000066400000000000000000000061401407704557200173160ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_is_root_of_unity(slong * p, ulong * q, const qqbar_t x) { ulong n; n = fmpz_poly_is_cyclotomic(QQBAR_POLY(x)); if (n == 0) return 0; if (q != NULL) *q = n; if (n == 1) { if (p != NULL) *p = 0; } else if (n == 2) { if (p != NULL) *p = 1; } else if (n == 3) { if (p != NULL) *p = (qqbar_sgn_im(x) > 0) ? 1 : 2; } else if (n == 4) { if (p != NULL) *p = (qqbar_sgn_im(x) > 0) ? 1 : 3; } else { if (p != NULL) { arb_t t, u; acb_t z; fmpz_t k; slong prec; acb_init(z); arb_init(t); arb_init(u); fmpz_init(k); prec = 64; /* more than enough */ qqbar_get_acb(z, x, prec); acb_arg(t, z, prec); arb_const_pi(u, prec); arb_div(t, t, u, prec); arb_mul_2exp_si(t, t, -1); arb_mul_ui(t, t, n, prec); if (!arb_get_unique_fmpz(k, t)) { flint_printf("qqbar_is_root_of_unity: unexpected precision issue\n"); flint_abort(); } if (fmpz_sgn(k) < 0) fmpz_add_ui(k, k, n); *p = fmpz_get_si(k); acb_clear(z); arb_clear(t); arb_clear(u); fmpz_clear(k); } } return 1; } void qqbar_root_of_unity(qqbar_t res, slong p, ulong q) { fmpq_t t; ulong a, b; slong prec; fmpq_init(t); if (q == 0) { flint_printf("qqbar_root_of_unity: q = 0\n"); flint_abort(); } fmpq_set_si(t, p, q); fmpz_fdiv_r(fmpq_numref(t), fmpq_numref(t), fmpq_denref(t)); a = fmpz_get_ui(fmpq_numref(t)); b = fmpz_get_ui(fmpq_denref(t)); if (a == 0) { qqbar_one(res); } else if (a == 1 && b == 2) { qqbar_set_si(res, -1); } else if (a == 1 && b == 4) { qqbar_i(res); } else if (a == 3 && b == 4) { qqbar_i(res); qqbar_conj(res, res); } else { fmpz_poly_cyclotomic(QQBAR_POLY(res), b); fmpq_mul_2exp(t, t, 1); for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { arb_sin_cos_pi_fmpq(acb_imagref(QQBAR_ENCLOSURE(res)), acb_realref(QQBAR_ENCLOSURE(res)), t, prec); /* todo: this is really unnecessary... */ if (_qqbar_validate_uniqueness(QQBAR_ENCLOSURE(res), QQBAR_POLY(res), QQBAR_ENCLOSURE(res), prec * 2)) { break; } } } fmpq_clear(t); } calcium-0.4.1/qqbar/root_ui.c000066400000000000000000000107571407704557200161100ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "flint/fmpz_poly_factor.h" #include "arb_fmpz_poly.h" #include "qqbar.h" int _qqbar_fast_detect_simple_principal_surd(const qqbar_t x) { slong d; d = qqbar_degree(x); if (d == 1) return 0; if (fmpz_sgn(QQBAR_COEFFS(x)) > 0) return 0; if (!_fmpz_vec_is_zero(QQBAR_COEFFS(x) + 1, d - 1)) return 0; /* Slow exact version, but we only want a fast check here. */ /* return qqbar_is_real(x) && qqbar_sgn_re(x) > 0; */ if (arb_is_zero(acb_imagref(QQBAR_ENCLOSURE(x)))) { if (arb_is_positive(acb_realref(QQBAR_ENCLOSURE(x)))) return 1; return 0; } if (!arb_contains_zero(acb_imagref(QQBAR_ENCLOSURE(x)))) return 0; /* The imaginary part enclosure may not be exactly zero; we can still use the enclosure if it is precise enough to guarantee that there are no collisions with the conjugate roots. */ if (acb_rel_accuracy_bits(QQBAR_ENCLOSURE(x)) > FLINT_BIT_COUNT(d) + 5) return arb_is_positive(acb_realref(QQBAR_ENCLOSURE(x))); return 0; } void qqbar_root_ui(qqbar_t res, const qqbar_t x, ulong n) { if (n == 0) { flint_printf("qqbar_root_ui: n >= 1 is required"); return; } else if (n == 1 || qqbar_is_zero(x) || qqbar_is_one(x)) { qqbar_set(res, x); } else { slong i, d, prec, found; fmpz_poly_t H; fmpz_poly_factor_t fac; acb_t z, w, t; int pure_real; d = qqbar_degree(x); if (FLINT_BIT_COUNT(n) + FLINT_BIT_COUNT(d) > 30) { flint_printf("qqbar_root_ui: ludicrously high degree %wd * %wu", d, n); return; } /* handle principal roots of positive rational numbers */ /* todo: could also handle conjugates of such roots */ if ((d == 1 && (n == 2 || qqbar_sgn_re(x) > 0)) || _qqbar_fast_detect_simple_principal_surd(x)) { fmpq_t t; fmpq_init(t); fmpz_neg(fmpq_numref(t), QQBAR_COEFFS(x)); fmpz_set(fmpq_denref(t), QQBAR_COEFFS(x) + d); qqbar_fmpq_root_ui(res, t, d * n); fmpq_clear(t); return; } /* special-case roots of unity */ /* todo: also specialize rational multiples of roots of unity */ { slong p; ulong q; if (qqbar_is_root_of_unity(&p, &q, x)) { if (2 * p > q) p -= q; qqbar_root_of_unity(res, p, q * n); return; } } fmpz_poly_init(H); fmpz_poly_factor_init(fac); acb_init(z); acb_init(w); acb_init(t); for (i = d; i >= 0; i--) { fmpz_poly_set_coeff_fmpz(H, i * n, QQBAR_COEFFS(x) + i); } fmpz_poly_factor(fac, H); acb_set(z, QQBAR_ENCLOSURE(x)); pure_real = qqbar_is_real(x); for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { _qqbar_enclosure_raw(z, QQBAR_POLY(x), z, prec); if (pure_real) arb_zero(acb_imagref(z)); acb_root_ui(w, z, n, prec); /* Look for potential roots -- we want exactly one */ found = -1; for (i = 0; i < fac->num && found != -2; i++) { arb_fmpz_poly_evaluate_acb(t, fac->p + i, w, prec); if (acb_contains_zero(t)) { if (found == -1) found = i; else found = -2; } } /* Check if the enclosure is good enough */ if (found >= 0) { if (_qqbar_validate_uniqueness(t, fac->p + found, w, 2 * prec)) { fmpz_poly_set(QQBAR_POLY(res), fac->p + found); acb_set(QQBAR_ENCLOSURE(res), t); break; } } } fmpz_poly_clear(H); fmpz_poly_factor_clear(fac); acb_clear(z); acb_clear(w); acb_clear(t); } } calcium-0.4.1/qqbar/roots_fmpq_poly.c000066400000000000000000000012261407704557200176530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_roots_fmpq_poly(qqbar_ptr res, const fmpq_poly_t poly, int flags) { fmpz_poly_t t; /* fake an fmpz_poly */ t->coeffs = poly->coeffs; t->length = poly->length; t->alloc = poly->alloc; qqbar_roots_fmpz_poly(res, t, flags); } calcium-0.4.1/qqbar/roots_fmpz_poly.c000066400000000000000000000061041407704557200176640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "flint/fmpz_poly_factor.h" #include "arb_fmpz_poly.h" #include "qqbar.h" void qqbar_roots_fmpz_poly(qqbar_ptr res, const fmpz_poly_t poly, int flags) { slong d = fmpz_poly_degree(poly); if (d == 0 || d == -1) return; if (d == 1) { fmpq_t t; fmpq_init(t); fmpz_neg(fmpq_numref(t), poly->coeffs); fmpz_set(fmpq_denref(t), poly->coeffs + 1); fmpq_canonicalise(t); /* irreducible, but may still have content */ qqbar_set_fmpq(res, t); fmpq_clear(t); return; } if (flags & QQBAR_ROOTS_IRREDUCIBLE) { slong prec, i, checked; fmpz_t c; acb_ptr croots; croots = _acb_vec_init(d); fmpz_init(c); fmpz_poly_content(c, poly); if (fmpz_sgn(poly->coeffs + d) < 0) fmpz_neg(c, c); for (prec = QQBAR_DEFAULT_PREC; ; prec *= 2) { arb_fmpz_poly_complex_roots(croots, poly, 0, prec); checked = 0; for (i = 0; i < d; i++) { if (_qqbar_validate_uniqueness(croots + i, poly, croots + i, prec)) checked++; else break; } if (checked == d) { for (i = 0; i < d; i++) { if (fmpz_is_one(c)) fmpz_poly_set(QQBAR_POLY(res + i), poly); else fmpz_poly_scalar_divexact_fmpz(QQBAR_POLY(res + i), poly, c); acb_set(QQBAR_ENCLOSURE(res + i), croots + i); } break; } } _acb_vec_clear(croots, d); fmpz_clear(c); } else { fmpz_poly_factor_t fac; qqbar_ptr out; slong i, j, k, e, facd; fmpz_poly_factor_init(fac); fmpz_poly_factor(fac, poly); out = res; for (i = 0; i < fac->num; i++) { facd = fmpz_poly_degree(fac->p + i); qqbar_roots_fmpz_poly(out, fac->p + i, QQBAR_ROOTS_IRREDUCIBLE); e = fac->exp[i]; /* duplicate entries with higher multiplicity */ if (e > 1) { for (j = facd - 1; j >= 0; j--) { qqbar_set(out + j * e, out + j); for (k = 1; k < e; k++) qqbar_set(out + j * e + k, out + j * e); } } out += e * facd; } fmpz_poly_factor_clear(fac); } if (!(flags & QQBAR_ROOTS_UNSORTED)) { qsort(res, d, sizeof(qqbar_struct), (int (*)(const void *, const void *)) qqbar_cmp_root_order); } } calcium-0.4.1/qqbar/sec_pi.c000066400000000000000000000010761407704557200156640ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_sec_pi(qqbar_t res, slong p, ulong q) { qqbar_cos_pi(res, p, q); if (qqbar_is_zero(res)) return 0; qqbar_inv(res, res); return 1; } calcium-0.4.1/qqbar/set.c000066400000000000000000000010641407704557200152120ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_set(qqbar_t res, const qqbar_t x) { fmpz_poly_set(QQBAR_POLY(res), QQBAR_POLY(x)); acb_set(QQBAR_ENCLOSURE(res), QQBAR_ENCLOSURE(x)); } calcium-0.4.1/qqbar/set_d.c000066400000000000000000000013701407704557200155150ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_set_d(qqbar_t res, double x) { arf_t t; fmpq_t u; int ok; arf_init(t); arf_set_d(t, x); if (arf_is_finite(t)) { fmpq_init(u); arf_get_fmpq(u, t); qqbar_set_fmpq(res, u); ok = 1; fmpq_clear(u); } else { ok = 0; } arf_clear(t); return ok; } calcium-0.4.1/qqbar/set_fexpr.c000066400000000000000000000730241407704557200164230ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" #include "fexpr.h" #include "fexpr_builtin.h" int qqbar_set_fexpr(qqbar_t res, const fexpr_t expr); int _fexpr_parse_arf(arf_t res, const fexpr_t expr) { if (fexpr_is_integer(expr)) { fmpz_t m; fmpz_init(m); fexpr_get_fmpz(m, expr); arf_set_fmpz(res, m); fmpz_clear(m); return 1; } if (fexpr_is_builtin_call(expr, FEXPR_Neg) && fexpr_nargs(expr) == 1) { int success; fexpr_t t; fexpr_view_arg(t, expr, 0); success = _fexpr_parse_arf(res, t); arf_neg(res, res); return success; } if (fexpr_is_builtin_call(expr, FEXPR_Div) && fexpr_nargs(expr) == 2) { int success; fexpr_t num, den; fmpz_t p, q; fexpr_view_arg(num, expr, 0); fexpr_view_arg(den, expr, 1); fmpz_init(p); fmpz_init(q); success = fexpr_get_fmpz(p, num) && fexpr_get_fmpz(q, den); success = success && (fmpz_sgn(q) > 0) && (fmpz_val2(q) == fmpz_bits(q) - 1); if (success) { arf_set_fmpz(res, p); arf_mul_2exp_si(res, res, -(fmpz_bits(q) - 1)); } fmpz_clear(p); fmpz_clear(q); return success; } if (fexpr_is_builtin_call(expr, FEXPR_Pow) && fexpr_nargs(expr) == 2) { fexpr_t base, exp; fexpr_view_arg(base, expr, 0); fexpr_view_arg(exp, expr, 1); if (fexpr_equal_ui(base, 2)) { fmpz_t m, e; int success; fmpz_init(m); fmpz_init(e); success = fexpr_get_fmpz(e, exp); if (success) { arf_one(res); arf_mul_2exp_fmpz(res, res, e); } fmpz_clear(m); fmpz_clear(e); return success; } } if (fexpr_is_builtin_call(expr, FEXPR_Mul) && fexpr_nargs(expr) == 2) { fexpr_t man, pow, base, exp; fexpr_view_arg(man, expr, 0); fexpr_view_arg(pow, expr, 1); if (fexpr_is_builtin_call(pow, FEXPR_Pow) && fexpr_nargs(expr) == 2) { fexpr_view_arg(base, pow, 0); fexpr_view_arg(exp, pow, 1); if (fexpr_equal_ui(base, 2)) { fmpz_t m, e; int success; fmpz_init(m); fmpz_init(e); success = fexpr_get_fmpz(m, man) && fexpr_get_fmpz(e, exp); if (success) { arf_set_fmpz(res, m); arf_mul_2exp_fmpz(res, res, e); } fmpz_clear(m); fmpz_clear(e); return success; } } } return 0; } int _fexpr_parse_mag(mag_t res, const fexpr_t expr) { int success; arf_t t; arf_init(t); success = _fexpr_parse_arf(t, expr); success = success && (arf_sgn(t) >= 0) && arf_is_finite(t) && (arf_bits(t) <= MAG_BITS); if (success) { fmpz_t m, e; fmpz_init(m); fmpz_init(e); arf_get_fmpz_2exp(m, e, t); mag_set_ui(res, fmpz_get_ui(m)); mag_mul_2exp_fmpz(res, res, e); fmpz_clear(m); fmpz_clear(e); } arf_clear(t); return success; } int _fexpr_parse_arb(arb_t res, const fexpr_t expr) { if (fexpr_is_builtin_call(expr, FEXPR_RealBall) && fexpr_nargs(expr) == 2) { fexpr_t t, u; fexpr_view_arg(t, expr, 0); fexpr_view_arg(u, expr, 1); return _fexpr_parse_arf(arb_midref(res), t) && _fexpr_parse_mag(arb_radref(res), u); } return 0; } int _fexpr_parse_acb(acb_t res, const fexpr_t expr) { fexpr_t t, u; if (fexpr_is_builtin_call(expr, FEXPR_RealBall) && fexpr_nargs(expr) == 2) { arb_zero(acb_imagref(res)); return _fexpr_parse_arb(acb_realref(res), expr); } if (fexpr_is_builtin_call(expr, FEXPR_Mul) && fexpr_nargs(expr) == 2) { fexpr_view_arg(t, expr, 1); if (!fexpr_is_builtin_symbol(t, FEXPR_NumberI)) return 0; fexpr_view_arg(u, expr, 0); arb_zero(acb_realref(res)); return _fexpr_parse_arb(acb_imagref(res), u); } if (fexpr_is_builtin_call(expr, FEXPR_Add) && fexpr_nargs(expr) == 2) { fexpr_view_arg(t, expr, 0); fexpr_view_arg(u, expr, 1); if (_fexpr_parse_acb(res, u) && arb_is_zero(acb_realref(res))) return _fexpr_parse_arb(acb_realref(res), t); } return 0; } int fmpq_set_decimal(fmpq_t res, const char * inp, slong max_bits) { char * emarker; char * buf; int success; slong i; fmpz_t exp; fmpz_t man; slong num_int, num_frac; int after_radix; if (inp[0] == '+') { return fmpq_set_decimal(res, inp + 1, max_bits); } if (inp[0] == '-') { success = fmpq_set_decimal(res, inp + 1, max_bits); fmpq_neg(res, res); return success; } success = 1; fmpz_init(exp); fmpz_init(man); buf = flint_malloc(strlen(inp) + 1); emarker = strchr(inp, 'e'); if (emarker == NULL) emarker = strchr(inp, 'E'); /* parse exponent (0 by default) */ if (emarker != NULL) { /* allow e+42 as well as e42 */ if (emarker[1] == '+') { if (!(emarker[2] >= '0' && emarker[2] <= '9')) success = 0; else success = !fmpz_set_str(exp, emarker + 2, 10); } else success = !fmpz_set_str(exp, emarker + 1, 10); if (!success) goto cleanup; } /* parse floating-point part */ { num_int = 0; num_frac = 0; after_radix = 0; for (i = 0; inp + i != emarker && inp[i] != '\0'; i++) { if (inp[i] == '.' && !after_radix) { after_radix = 1; } else if (inp[i] >= '0' && inp[i] <= '9') { buf[num_int + num_frac] = inp[i]; num_frac += after_radix; num_int += !after_radix; } else { success = 0; goto cleanup; } } buf[num_int + num_frac] = '\0'; /* put trailing zeros into the exponent */ while (num_int + num_frac > 1 && buf[num_int + num_frac - 1] == '0') { buf[num_int + num_frac - 1] = '\0'; num_frac--; } fmpz_sub_si(exp, exp, num_frac); success = !fmpz_set_str(man, buf, 10); if (!success) goto cleanup; } if (fmpz_is_zero(man)) { fmpq_zero(res); } else if (COEFF_IS_MPZ(*exp)) { success = 0; } else { slong e = *exp; double size; size = fmpz_bits(man) + e * 3.321928094887; size = fabs(size); if (size > max_bits) { success = 0; } else { if (e >= 0) { fmpz_set_ui(exp, 10); fmpz_pow_ui(exp, exp, e); fmpz_mul(fmpq_numref(res), man, exp); fmpz_one(fmpq_denref(res)); } else { fmpz_set_ui(exp, 10); fmpz_pow_ui(exp, exp, -e); fmpz_set(fmpq_numref(res), man); fmpz_set(fmpq_denref(res), exp); fmpq_canonicalise(res); } } } if (!success) { fmpq_zero(res); } cleanup: fmpz_clear(exp); fmpz_clear(man); flint_free(buf); return success; } static int _fexpr_check_pi_in_product(const fexpr_t expr) { fexpr_t func, arg, arg2; slong i, nargs; int status, arg_status; if (fexpr_is_atom(expr)) { if (fexpr_is_builtin_symbol(expr, FEXPR_Pi)) return 1; return 0; } nargs = fexpr_nargs(expr); fexpr_view_func(func, expr); if (nargs == 1 && (fexpr_is_builtin_symbol(func, FEXPR_Neg) || fexpr_is_builtin_symbol(func, FEXPR_Pos))) { fexpr_view_arg(arg, expr, 0); return _fexpr_check_pi_in_product(arg); } if (nargs == 2 && (fexpr_is_builtin_symbol(func, FEXPR_Div))) { fexpr_view_arg(arg, expr, 0); fexpr_view_arg(arg2, expr, 1); if (_fexpr_check_pi_in_product(arg2) != 0) return -1; return _fexpr_check_pi_in_product(arg); } if (nargs >= 1 && (fexpr_is_builtin_symbol(func, FEXPR_Mul))) { status = 0; fexpr_view_arg(arg, expr, 0); for (i = 0; i < nargs; i++) { arg_status = _fexpr_check_pi_in_product(arg); if (arg_status == -1) return -1; if (arg_status == 1 && status == 1) return -1; if (arg_status == 1) status = 1; fexpr_view_next(arg); } return status; } return -1; } static int _fexpr_get_rational_arg_pi(fmpq_t res, const fexpr_t expr, int times_i) { int status, success; status = _fexpr_check_pi_in_product(expr); if (status == 0 || status == 1) { fexpr_t tmp, pi, one; qqbar_t v, i; fexpr_init(tmp); fexpr_init(pi); fexpr_init(one); qqbar_init(v); fexpr_set_symbol_builtin(pi, FEXPR_Pi); fexpr_set_si(one, 1); fexpr_replace(tmp, expr, pi, one); success = qqbar_set_fexpr(v, tmp); if (success) { if (times_i) { qqbar_init(i); qqbar_i(i); qqbar_div(v, v, i); qqbar_clear(i); } success = qqbar_is_rational(v); if (success) { fmpz_neg(fmpq_numref(res), QQBAR_COEFFS(v)); fmpz_set(fmpq_denref(res), QQBAR_COEFFS(v) + 1); } } fexpr_clear(tmp); fexpr_clear(pi); fexpr_clear(one); qqbar_clear(v); return success; } return 0; } void qqbar_set_fmpz_poly_root_indexed(qqbar_t res, const fmpz_poly_t poly, slong root_index) { qqbar_ptr roots; slong d; d = fmpz_poly_degree(poly); roots = _qqbar_vec_init(d); qqbar_roots_fmpz_poly(roots, poly, 0); qqbar_set(res, roots + root_index - 1); _qqbar_vec_clear(roots, d); } void qqbar_set_fmpz_poly_root_nearest(qqbar_t res, const fmpz_poly_t poly, const qqbar_t point) { qqbar_ptr roots; slong i, best, d; acb_t t; arb_t distance, best_distance; int overlapping; d = fmpz_poly_degree(poly); roots = _qqbar_vec_init(d); acb_init(t); arb_init(distance); arb_init(best_distance); qqbar_roots_fmpz_poly(roots, poly, 0); acb_sub(t, QQBAR_ENCLOSURE(point), QQBAR_ENCLOSURE(roots), QQBAR_DEFAULT_PREC); acb_abs(best_distance, t, QQBAR_DEFAULT_PREC); best = 0; overlapping = 0; for (i = 1; i < d; i++) { acb_sub(t, QQBAR_ENCLOSURE(point), QQBAR_ENCLOSURE(roots + i), QQBAR_DEFAULT_PREC); acb_abs(distance, t, QQBAR_DEFAULT_PREC); if (arb_lt(distance, best_distance)) { arb_swap(best_distance, distance); best = i; overlapping = 0; } else if (arb_overlaps(distance, best_distance)) { overlapping = 1; } } if (overlapping) { qqbar_t exact_distance, best_exact_distance; qqbar_init(exact_distance); qqbar_init(best_exact_distance); qqbar_sub(best_exact_distance, point, roots + best); qqbar_abs2(best_exact_distance, best_exact_distance); for (i = 0; i < d; i++) { if (i != best) { acb_sub(t, QQBAR_ENCLOSURE(point), QQBAR_ENCLOSURE(roots + i), QQBAR_DEFAULT_PREC); acb_abs(distance, t, QQBAR_DEFAULT_PREC); if (arb_gt(distance, best_distance)) continue; qqbar_sub(exact_distance, point, roots + i); qqbar_abs2(exact_distance, exact_distance); if (qqbar_cmp_re(exact_distance, best_exact_distance) < 0) { qqbar_swap(best_exact_distance, exact_distance); best = i; } } } qqbar_clear(exact_distance); qqbar_clear(best_exact_distance); } qqbar_swap(res, roots + best); acb_clear(t); arb_clear(distance); arb_clear(best_distance); _qqbar_vec_clear(roots, d); } int qqbar_set_fexpr(qqbar_t res, const fexpr_t expr) { fexpr_t func, arg; slong id, i, nargs; qqbar_t t; fmpq_t q; int success; if (fexpr_is_integer(expr)) { fmpz_t t; fmpz_init(t); fexpr_get_fmpz(t, expr); qqbar_set_fmpz(res, t); fmpz_clear(t); return 1; } if (fexpr_is_atom(expr)) { if (fexpr_is_builtin_symbol(expr, FEXPR_NumberI)) { qqbar_i(res); return 1; } if (fexpr_is_builtin_symbol(expr, FEXPR_GoldenRatio)) { qqbar_phi(res); return 1; } return 0; } nargs = fexpr_nargs(expr); fexpr_view_func(func, expr); id = FEXPR_BUILTIN_ID(func->data[0]); switch (id) { case FEXPR_AlgebraicNumberSerialized: case FEXPR_PolynomialRootIndexed: case FEXPR_PolynomialRootNearest: if (nargs == 2) { slong root_index = 0; fexpr_view_arg(arg, expr, 1); if (id == FEXPR_PolynomialRootIndexed) { fmpz_t tmp; fmpz_init(tmp); success = fexpr_get_fmpz(tmp, arg); root_index = *tmp; success = success && (root_index >= 1 && root_index <= COEFF_MAX); fmpz_clear(tmp); } else if (id == FEXPR_PolynomialRootNearest) { root_index = 1; success = qqbar_set_fexpr(res, arg); } else { success = _fexpr_parse_acb(QQBAR_ENCLOSURE(res), arg); } fexpr_view_arg(arg, expr, 0); success = success && fexpr_is_builtin_call(arg, FEXPR_List); if (success) { slong deg, len; len = fexpr_nargs(arg); deg = len - 1; success = (deg >= 1) && (deg >= root_index); if (success) { fmpz_poly_t poly; fexpr_t c; fmpz_poly_init2(poly, len); _fmpz_poly_set_length(poly, len); fexpr_view_arg(c, arg, 0); for (i = 0; i < len && success; i++) { success = fexpr_get_fmpz(poly->coeffs + i, c); fexpr_view_next(c); } if (success) { _fmpz_poly_normalise(poly); deg = fmpz_poly_degree(poly); success = (deg >= root_index); if (success && id == FEXPR_PolynomialRootIndexed) qqbar_set_fmpz_poly_root_indexed(res, poly, root_index); else if (success && id == FEXPR_PolynomialRootNearest) qqbar_set_fmpz_poly_root_nearest(res, poly, res); else if (success) fmpz_poly_swap(QQBAR_POLY(res), poly); } fmpz_poly_clear(poly); return success; } } } break; case FEXPR_Decimal: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = fexpr_is_string(arg); if (success) { char * s = fexpr_get_string(arg); fmpq_init(q); success = fmpq_set_decimal(q, s, COEFF_MAX); if (success) { qqbar_set_fmpq(res, q); } flint_free(s); fmpq_clear(q); } return success; } break; case FEXPR_RootOfUnity: if (nargs == 1 || nargs == 2) { fmpz_t n, k; fmpz_init(n); fmpz_init(k); qqbar_init(t); fmpz_one(k); fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(t, arg) && qqbar_is_integer(t) && (qqbar_sgn_re(t) == 1); if (success) fmpz_neg(n, QQBAR_COEFFS(t)); success = success && !COEFF_IS_MPZ(*n); if (success && nargs == 2) { fexpr_view_arg(arg, expr, 1); success = qqbar_set_fexpr(res, arg) && qqbar_is_integer(res); if (success) { fmpz_neg(k, QQBAR_COEFFS(res)); fmpz_fdiv_r(k, k, n); } } if (success) qqbar_root_of_unity(res, *k, *n); fmpz_clear(n); fmpz_clear(k); qqbar_clear(t); return success; } break; case FEXPR_Exp: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); fmpq_init(q); success = _fexpr_get_rational_arg_pi(q, arg, 1); if (success && !COEFF_IS_MPZ(*fmpq_numref(q)) && !COEFF_IS_MPZ(*fmpq_denref(q))) qqbar_exp_pi_i(res, *fmpq_numref(q), *fmpq_denref(q)); fmpq_clear(q); return success; } break; case FEXPR_Sin: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); fmpq_init(q); success = _fexpr_get_rational_arg_pi(q, arg, 0); if (success && !COEFF_IS_MPZ(*fmpq_numref(q)) && !COEFF_IS_MPZ(*fmpq_denref(q))) qqbar_sin_pi(res, *fmpq_numref(q), *fmpq_denref(q)); fmpq_clear(q); return success; } break; case FEXPR_Cos: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); fmpq_init(q); success = _fexpr_get_rational_arg_pi(q, arg, 0); if (success && !COEFF_IS_MPZ(*fmpq_numref(q)) && !COEFF_IS_MPZ(*fmpq_denref(q))) qqbar_cos_pi(res, *fmpq_numref(q), *fmpq_denref(q)); fmpq_clear(q); return success; } break; case FEXPR_Tan: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); fmpq_init(q); success = _fexpr_get_rational_arg_pi(q, arg, 0); if (success && !COEFF_IS_MPZ(*fmpq_numref(q)) && !COEFF_IS_MPZ(*fmpq_denref(q))) success = qqbar_tan_pi(res, *fmpq_numref(q), *fmpq_denref(q)); fmpq_clear(q); return success; } break; case FEXPR_Cot: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); fmpq_init(q); success = _fexpr_get_rational_arg_pi(q, arg, 0); if (success && !COEFF_IS_MPZ(*fmpq_numref(q)) && !COEFF_IS_MPZ(*fmpq_denref(q))) success = qqbar_cot_pi(res, *fmpq_numref(q), *fmpq_denref(q)); fmpq_clear(q); return success; } break; case FEXPR_Sec: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); fmpq_init(q); success = _fexpr_get_rational_arg_pi(q, arg, 0); if (success && !COEFF_IS_MPZ(*fmpq_numref(q)) && !COEFF_IS_MPZ(*fmpq_denref(q))) success = qqbar_sec_pi(res, *fmpq_numref(q), *fmpq_denref(q)); fmpq_clear(q); return success; } break; case FEXPR_Csc: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); fmpq_init(q); success = _fexpr_get_rational_arg_pi(q, arg, 0); if (success && !COEFF_IS_MPZ(*fmpq_numref(q)) && !COEFF_IS_MPZ(*fmpq_denref(q))) success = qqbar_csc_pi(res, *fmpq_numref(q), *fmpq_denref(q)); fmpq_clear(q); return success; } break; case FEXPR_Pos: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); return success; } break; case FEXPR_Neg: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) qqbar_neg(res, res); return success; } break; case FEXPR_Sqrt: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) qqbar_sqrt(res, res); return success; } break; case FEXPR_Conjugate: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) qqbar_conj(res, res); return success; } break; case FEXPR_Re: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) qqbar_re(res, res); return success; } break; case FEXPR_Im: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) qqbar_im(res, res); return success; } break; case FEXPR_Floor: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) { fmpz_t n; fmpz_init(n); qqbar_floor(n, res); qqbar_set_fmpz(res, n); fmpz_clear(n); } return success; } break; case FEXPR_Ceil: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) { fmpz_t n; fmpz_init(n); qqbar_ceil(n, res); qqbar_set_fmpz(res, n); fmpz_clear(n); } return success; } break; case FEXPR_Abs: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) qqbar_abs(res, res); return success; } break; case FEXPR_Sign: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) qqbar_sgn(res, res); return success; } break; case FEXPR_Csgn: if (nargs == 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) qqbar_set_si(res, qqbar_csgn(res)); return success; } break; case FEXPR_Sub: if (nargs == 2) { qqbar_init(t); fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) { fexpr_view_next(arg); success = qqbar_set_fexpr(t, arg); if (success) qqbar_sub(res, res, t); } qqbar_clear(t); return success; } break; case FEXPR_Div: if (nargs == 2) { qqbar_init(t); fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) { fexpr_view_next(arg); success = qqbar_set_fexpr(t, arg); success = success && !qqbar_is_zero(t); if (success) qqbar_div(res, res, t); } qqbar_clear(t); return success; } break; case FEXPR_Pow: if (nargs == 2) { qqbar_init(t); fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success) { fexpr_view_next(arg); success = qqbar_set_fexpr(t, arg); success = success && qqbar_is_rational(t) && (!qqbar_is_zero(res) || qqbar_sgn_re(t) >= 0); if (success) { fmpz_t p, q; fmpz_init(p); fmpz_init(q); fmpz_neg(p, QQBAR_COEFFS(t)); fmpz_set(q, QQBAR_COEFFS(t) + 1); success = (fmpz_bits(q) <= 20 && fmpz_bits(p) <= FLINT_BITS - 4); if (success) { qqbar_root_ui(res, res, *q); if (*p >= 0) qqbar_pow_ui(res, res, *p); else { qqbar_pow_ui(res, res, -(*p)); qqbar_inv(res, res); } } } } qqbar_clear(t); return success; } break; case FEXPR_Add: if (nargs == 0) { qqbar_zero(res); return 1; } fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success && nargs > 1) { qqbar_init(t); for (i = 1; i < nargs && success; i++) { fexpr_view_next(arg); success = qqbar_set_fexpr(t, arg); if (success) qqbar_add(res, res, t); } qqbar_clear(t); } return success; case FEXPR_Mul: if (nargs == 0) { qqbar_one(res); return 1; } fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg); if (success && nargs > 1) { qqbar_init(t); for (i = 1; i < nargs && success; i++) { fexpr_view_next(arg); success = qqbar_set_fexpr(t, arg); if (success) qqbar_mul(res, res, t); } qqbar_clear(t); } return success; case FEXPR_Min: case FEXPR_Max: if (nargs >= 1) { fexpr_view_arg(arg, expr, 0); success = qqbar_set_fexpr(res, arg) && qqbar_is_real(res); if (success && nargs >= 2) { qqbar_init(t); for (i = 1; i < nargs && success; i++) { fexpr_view_next(arg); success = qqbar_set_fexpr(t, arg) && qqbar_is_real(t); if (success) { if ((qqbar_cmp_re(res, t) < 0) == (id == FEXPR_Max)) qqbar_swap(res, t); } } qqbar_clear(t); } return success; } default: break; } return 0; } calcium-0.4.1/qqbar/set_fmpq.c000066400000000000000000000012451407704557200162360ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_set_fmpq(qqbar_t res, const fmpq_t x) { fmpz_poly_zero(QQBAR_POLY(res)); fmpz_poly_set_coeff_fmpz(QQBAR_POLY(res), 1, fmpq_denref(x)); fmpz_neg(QQBAR_COEFFS(res), fmpq_numref(x)); acb_set_fmpq(QQBAR_ENCLOSURE(res), x, QQBAR_DEFAULT_PREC); } calcium-0.4.1/qqbar/set_fmpz.c000066400000000000000000000012171407704557200162460ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_set_fmpz(qqbar_t res, const fmpz_t x) { fmpz_poly_zero(QQBAR_POLY(res)); fmpz_poly_set_coeff_si(QQBAR_POLY(res), 1, 1); fmpz_neg(QQBAR_COEFFS(res), x); acb_set_round_fmpz(QQBAR_ENCLOSURE(res), x, QQBAR_DEFAULT_PREC); } calcium-0.4.1/qqbar/set_re_im.c000066400000000000000000000014241407704557200163650ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_set_re_im(qqbar_t res, const qqbar_t x, const qqbar_t y) { if (qqbar_is_zero(y)) { qqbar_set(res, x); } else { qqbar_t t, u; qqbar_init(t); qqbar_init(u); qqbar_set(t, y); qqbar_i(u); qqbar_mul(t, t, u); qqbar_add(res, x, t); qqbar_clear(t); qqbar_clear(u); } } calcium-0.4.1/qqbar/set_re_im_d.c000066400000000000000000000016361407704557200166750ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_set_re_im_d(qqbar_t res, double x, double y) { int ok; if (y == 0.0) { ok = qqbar_set_d(res, x); } else { ok = qqbar_set_d(res, y); if (ok) { qqbar_t t; qqbar_init(t); qqbar_i(t); qqbar_mul(res, res, t); if (x != 0) { ok = qqbar_set_d(t, x); qqbar_add(res, res, t); } qqbar_clear(t); } } return ok; } calcium-0.4.1/qqbar/set_si.c000066400000000000000000000010361407704557200157040ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_set_si(qqbar_t res, slong x) { fmpz_t t; fmpz_init_set_si(t, x); qqbar_set_fmpz(res, t); fmpz_clear(t); } calcium-0.4.1/qqbar/set_ui.c000066400000000000000000000010361407704557200157060ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_set_ui(qqbar_t res, ulong x) { fmpz_t t; fmpz_init_set_ui(t, x); qqbar_set_fmpz(res, t); fmpz_clear(t); } calcium-0.4.1/qqbar/sgn.c000066400000000000000000000015061407704557200152070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_sgn(qqbar_t res, const qqbar_t x) { int re, im; re = qqbar_sgn_re(x); im = qqbar_sgn_im(x); if (im == 0) { qqbar_set_si(res, re); } else if (re == 0) { qqbar_i(res); if (im < 0) qqbar_neg(res, res); } else { qqbar_t t; qqbar_init(t); qqbar_abs(t, x); qqbar_div(res, x, t); qqbar_clear(t); } } calcium-0.4.1/qqbar/sgn_im.c000066400000000000000000000032161407704557200156740ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_sgn_im(const qqbar_t x) { if (qqbar_degree(x) == 1) { return 0; } else if (arb_is_zero(acb_imagref(QQBAR_ENCLOSURE(x)))) { return 0; } else if (!arb_contains_zero(acb_imagref(QQBAR_ENCLOSURE(x)))) { return arf_sgn(arb_midref(acb_imagref(QQBAR_ENCLOSURE(x)))); } else { slong prec; int res; acb_t t, u; acb_init(t); acb_init(u); acb_set(t, QQBAR_ENCLOSURE(x)); res = 0; for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { _qqbar_enclosure_raw(t, QQBAR_POLY(x), t, prec); if (!arb_contains_zero(acb_imagref(t)) || arb_is_zero(acb_imagref(t))) { res = arf_sgn(arb_midref(acb_imagref(t))); break; } #if 0 acb_conj(u, t); acb_union(u, u, t, prec); if (_qqbar_validate_uniqueness(u, QQBAR_POLY(x), u, 2 * prec)) break; #else acb_set(u, t); arb_zero(acb_imagref(u)); if (_qqbar_validate_existence_uniqueness(u, QQBAR_POLY(x), u, 2 * prec)) break; #endif } acb_clear(t); acb_clear(u); return res; } } calcium-0.4.1/qqbar/sgn_re.c000066400000000000000000000035241407704557200156770ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_sgn_re(const qqbar_t x) { if (qqbar_degree(x) == 1) { return -fmpz_sgn(QQBAR_COEFFS(x)); } else if (arb_is_zero(acb_realref(QQBAR_ENCLOSURE(x)))) { return 0; } else if (!arb_contains_zero(acb_realref(QQBAR_ENCLOSURE(x)))) { return arf_sgn(arb_midref(acb_realref(QQBAR_ENCLOSURE(x)))); } else { slong d, i; slong prec; int res, maybe_zero; acb_t t, u; acb_init(t); acb_init(u); d = qqbar_degree(x); maybe_zero = 1; for (i = 1; i < d && maybe_zero; i += 2) if (!fmpz_is_zero(QQBAR_COEFFS(x) + i)) maybe_zero = 0; acb_set(t, QQBAR_ENCLOSURE(x)); res = 0; for (prec = QQBAR_DEFAULT_PREC / 2; ; prec *= 2) { _qqbar_enclosure_raw(t, QQBAR_POLY(x), t, prec); if (!arb_contains_zero(acb_realref(t)) || arb_is_zero(acb_realref(t))) { res = arf_sgn(arb_midref(acb_realref(t))); break; } if (maybe_zero) { acb_set(u, t); arb_zero(acb_realref(u)); if (_qqbar_validate_existence_uniqueness(u, QQBAR_POLY(x), u, prec * 2)) { res = 0; break; } } } acb_clear(t); acb_clear(u); return res; } } calcium-0.4.1/qqbar/sin_pi.c000066400000000000000000000010341407704557200156750ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_sin_pi(qqbar_t res, slong p, ulong q) { p = p % (2 * (slong) q); qqbar_cos_pi(res, (slong) q - 2 * p, 2 * q); } calcium-0.4.1/qqbar/sub.c000066400000000000000000000053451407704557200152160ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_sub(qqbar_t res, const qqbar_t x, const qqbar_t y) { if (qqbar_is_zero(x)) { qqbar_neg(res, y); } else if (qqbar_is_zero(y)) { qqbar_set(res, x); } else if (qqbar_is_rational(y)) { fmpz_t a, b, c; fmpz_init(a); fmpz_init(b); fmpz_init(c); fmpz_set(a, QQBAR_COEFFS(y) + 1); fmpz_set(b, QQBAR_COEFFS(y)); fmpz_set(c, QQBAR_COEFFS(y) + 1); qqbar_scalar_op(res, x, a, b, c); fmpz_clear(a); fmpz_clear(b); fmpz_clear(c); } else if (qqbar_is_rational(x)) { fmpz_t a, b, c; fmpz_init(a); fmpz_init(b); fmpz_init(c); fmpz_neg(a, QQBAR_COEFFS(x) + 1); fmpz_neg(b, QQBAR_COEFFS(x)); fmpz_set(c, QQBAR_COEFFS(x) + 1); qqbar_scalar_op(res, y, a, b, c); fmpz_clear(a); fmpz_clear(b); fmpz_clear(c); } else { qqbar_binary_op(res, x, y, 1); } } void qqbar_sub_fmpq(qqbar_t res, const qqbar_t x, const fmpq_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpq(t, y); qqbar_sub(res, x, t); qqbar_clear(t); } void qqbar_sub_fmpz(qqbar_t res, const qqbar_t x, const fmpz_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpz(t, y); qqbar_sub(res, x, t); qqbar_clear(t); } void qqbar_sub_ui(qqbar_t res, const qqbar_t x, ulong y) { qqbar_t t; qqbar_init(t); qqbar_set_ui(t, y); qqbar_sub(res, x, t); qqbar_clear(t); } void qqbar_sub_si(qqbar_t res, const qqbar_t x, slong y) { qqbar_t t; qqbar_init(t); qqbar_set_si(t, y); qqbar_sub(res, x, t); qqbar_clear(t); } void qqbar_fmpq_sub(qqbar_t res, const fmpq_t x, const qqbar_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpq(t, x); qqbar_sub(res, t, y); qqbar_clear(t); } void qqbar_fmpz_sub(qqbar_t res, const fmpz_t x, const qqbar_t y) { qqbar_t t; qqbar_init(t); qqbar_set_fmpz(t, x); qqbar_sub(res, t, y); qqbar_clear(t); } void qqbar_ui_sub(qqbar_t res, ulong x, const qqbar_t y) { qqbar_t t; qqbar_init(t); qqbar_set_ui(t, x); qqbar_sub(res, t, y); qqbar_clear(t); } void qqbar_si_sub(qqbar_t res, slong x, const qqbar_t y) { qqbar_t t; qqbar_init(t); qqbar_set_si(t, x); qqbar_sub(res, t, y); qqbar_clear(t); } calcium-0.4.1/qqbar/swap.c000066400000000000000000000010531407704557200153670ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" void qqbar_swap(qqbar_t x, qqbar_t y) { fmpz_poly_swap(QQBAR_POLY(x), QQBAR_POLY(y)); acb_swap(QQBAR_ENCLOSURE(x), QQBAR_ENCLOSURE(y)); } calcium-0.4.1/qqbar/tan_pi.c000066400000000000000000000030371407704557200156730ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_tan_pi(qqbar_t res, slong p, ulong q) { slong g; g = n_gcd(FLINT_ABS(p), q); if (g != 1) { p /= g; q /= g; } if (q == 1) { qqbar_zero(res); } else if (q == 2) { return 0; } else if (q == 4) { if (p % 4 == 1 || p % 4 == -3) qqbar_one(res); else qqbar_set_si(res, -1); } else if (q == 3) { qqbar_set_ui(res, 3); qqbar_sqrt(res, res); if (p % 3 == -1 || p % 3 == 2) qqbar_neg(res, res); } else if (q == 6) { qqbar_set_ui(res, 3); qqbar_sqrt(res, res); qqbar_inv(res, res); if (p % 6 == -1 || p % 6 == 5) qqbar_neg(res, res); } else { qqbar_t t; qqbar_init(t); qqbar_exp_pi_i(res, 2 * p, q); qqbar_add_ui(res, res, 1); qqbar_inv(res, res); qqbar_mul_2exp_si(res, res, 1); qqbar_sub_ui(res, res, 1); qqbar_i(t); qqbar_mul(res, res, t); arb_zero(acb_imagref(QQBAR_ENCLOSURE(res))); qqbar_clear(t); } return 1; } calcium-0.4.1/qqbar/test/000077500000000000000000000000001407704557200152315ustar00rootroot00000000000000calcium-0.4.1/qqbar/test/t-abs.c000066400000000000000000000032541407704557200164070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("abs...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, t, u; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(t); qqbar_init(u); qqbar_randtest(x, state, 3, 10); qqbar_randtest(y, state, 3, 10); qqbar_abs(z, x); qqbar_abs(t, y); qqbar_mul(t, t, z); qqbar_mul(u, x, y); qqbar_abs(u, u); if (!qqbar_equal(t, u) || !qqbar_is_real(t)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("t = "); qqbar_print(t); flint_printf("\n\n"); flint_printf("u = "); qqbar_print(t); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(t); qqbar_clear(u); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-abs2.c000066400000000000000000000025041407704557200164660ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("abs2...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_randtest(x, state, 3, 10); qqbar_abs2(y, x); qqbar_abs(z, x); qqbar_sqr(z, z); if (!qqbar_equal(y, z)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-acos_pi.c000066400000000000000000000031741407704557200172600ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("acos_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; slong p, p2; ulong q, q2; int res; qqbar_init(x); qqbar_init(y); q = 1 + n_randint(state, 30); q = 1 + n_randint(state, q); p = n_randint(state, 1000); p -= 500; qqbar_cos_pi(x, p, q); res = qqbar_acos_pi(&p2, &q2, x); if (res) qqbar_cos_pi(y, p2, q2); if (!res || !qqbar_equal(x, y) || n_gcd(FLINT_ABS(p2), q2) != 1 || !(0 <= p2 && p2 <= (slong) q2)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("res = %d\n\n", res); flint_printf("p, p2 = %wd %wd\n\n", p, p2); flint_printf("q, q2 = %wu %wu\n\n", q, q2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-acot_pi.c000066400000000000000000000033461407704557200172620ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("acot_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; slong p, p2; ulong q, q2; int res; qqbar_init(x); qqbar_init(y); do { q = 1 + n_randint(state, 15); p = n_randint(state, 1000); p -= 500; /* Don't generate poles */ } while ((q / n_gcd(FLINT_ABS(p), q) == 1)); qqbar_cot_pi(x, p, q); res = qqbar_acot_pi(&p2, &q2, x); if (res) qqbar_cot_pi(y, p2, q2); if (!res || !qqbar_equal(x, y) || n_gcd(FLINT_ABS(p2), q2) != 1 || !(-(slong) q2 < 2 * p2 && 2 * p2 <= (slong) q2)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("res = %d\n\n", res); flint_printf("p, p2 = %wd %wd\n\n", p, p2); flint_printf("q, q2 = %wu %wu\n\n", q, q2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-acsc_pi.c000066400000000000000000000033471407704557200172460ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("asec_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; slong p, p2; ulong q, q2; int res; qqbar_init(x); qqbar_init(y); do { q = 1 + n_randint(state, 15); p = n_randint(state, 1000); p -= 500; /* Don't generate poles */ } while ((q / n_gcd(FLINT_ABS(p), q) == 1)); qqbar_csc_pi(x, p, q); res = qqbar_acsc_pi(&p2, &q2, x); if (res) qqbar_csc_pi(y, p2, q2); if (!res || !qqbar_equal(x, y) || n_gcd(FLINT_ABS(p2), q2) != 1 || !(-(slong) q2 <= 2 * p2 && 2 * p2 <= (slong) q2)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("res = %d\n\n", res); flint_printf("p, p2 = %wd %wd\n\n", p, p2); flint_printf("q, q2 = %wu %wu\n\n", q, q2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-add.c000066400000000000000000000122651407704557200163740ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("add...."); fflush(stdout); flint_randinit(state); /* Check addition with degree-1 terms, large coefficients */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 20, 100); qqbar_randtest(y, state, 1, 100); qqbar_randtest(z, state, 1, 100); /* check (x + y) + z = x + (y + z) */ qqbar_add(a, x, y); qqbar_add(a, a, z); qqbar_add(b, y, z); qqbar_add(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* Check addition with degree-1 terms, small coefficients */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 30, 10); qqbar_randtest(y, state, 1, 10); qqbar_randtest(z, state, 1, 10); /* check (x + y) + z = x + (y + z) */ qqbar_add(a, x, y); qqbar_add(a, a, z); qqbar_add(b, y, z); qqbar_add(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* Check addition with higher-degree terms */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 6, 10); qqbar_randtest(y, state, 6, 10); qqbar_randtest(z, state, 2, 10); /* check (x + y) + z = x + (y + z) */ qqbar_add(a, x, y); qqbar_add(a, a, z); qqbar_add(b, y, z); qqbar_add(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* More iterations, low degree */ for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 4, 10); qqbar_randtest(y, state, 3, 10); qqbar_randtest(z, state, 2, 10); /* check (x + y) + z = x + (y + z) */ qqbar_add(a, x, y); qqbar_add(a, a, z); qqbar_add(b, y, z); qqbar_add(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-asec_pi.c000066400000000000000000000033251407704557200172440ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("asec_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; slong p, p2; ulong q, q2; int res; qqbar_init(x); qqbar_init(y); do { q = 1 + n_randint(state, 15); p = n_randint(state, 1000); p -= 500; /* Don't generate poles */ } while ((q / n_gcd(FLINT_ABS(p), q) == 2)); qqbar_sec_pi(x, p, q); res = qqbar_asec_pi(&p2, &q2, x); if (res) qqbar_sec_pi(y, p2, q2); if (!res || !qqbar_equal(x, y) || n_gcd(FLINT_ABS(p2), q2) != 1 || !(0 <= p2 && p2 <= (slong) q2)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("res = %d\n\n", res); flint_printf("p, p2 = %wd %wd\n\n", p, p2); flint_printf("q, q2 = %wu %wu\n\n", q, q2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-asin_pi.c000066400000000000000000000032161407704557200172620ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("asin_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; slong p, p2; ulong q, q2; int res; qqbar_init(x); qqbar_init(y); q = 1 + n_randint(state, 30); q = 1 + n_randint(state, q); p = n_randint(state, 1000); p -= 500; qqbar_sin_pi(x, p, q); res = qqbar_asin_pi(&p2, &q2, x); if (res) qqbar_sin_pi(y, p2, q2); if (!res || !qqbar_equal(x, y) || n_gcd(FLINT_ABS(p2), q2) != 1 || !(-(slong) q2 <= 2 * p2 && 2 * p2 <= (slong) q2)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("res = %d\n\n", res); flint_printf("p, p2 = %wd %wd\n\n", p, p2); flint_printf("q, q2 = %wu %wu\n\n", q, q2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-atan_pi.c000066400000000000000000000034141407704557200172530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("atan_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; slong p, p2; ulong q, q2; int res; qqbar_init(x); qqbar_init(y); do { q = 1 + n_randint(state, 15); q = 1 + n_randint(state, q); p = n_randint(state, 1000); p -= 500; /* Don't generate poles */ } while (q / n_gcd(FLINT_ABS(p), q) == 2); qqbar_tan_pi(x, p, q); res = qqbar_atan_pi(&p2, &q2, x); if (res) qqbar_tan_pi(y, p2, q2); if (!res || !qqbar_equal(x, y) || n_gcd(FLINT_ABS(p2), q2) != 1 || !(-(slong) q2 < 2 * p2 && 2 * p2 < (slong) q2)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("res = %d\n\n", res); flint_printf("p, p2 = %wd %wd\n\n", p, p2); flint_printf("q, q2 = %wu %wu\n\n", q, q2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-ceil.c000066400000000000000000000040671407704557200165610ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("ceil...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, t, u; fmpz_t n, n1; int ok; qqbar_init(x); qqbar_init(y); qqbar_init(t); qqbar_init(u); fmpz_init(n); fmpz_init(n1); if (n_randint(state, 2)) { qqbar_randtest(x, state, 4, 200); } else { fmpq_t c; fmpq_init(c); fmpz_randtest(n, state, 400); fmpq_randtest(c, state, 400); fmpq_add_fmpz(c, c, n); fmpz_zero(n); qqbar_set_fmpq(x, c); qqbar_randtest(y, state, 1, 100); qqbar_i(t); qqbar_mul(y, y, t); qqbar_add(x, x, y); fmpq_clear(c); } qqbar_ceil(n, x); fmpz_sub_ui(n1, n, 1); qqbar_set_fmpz(t, n); qqbar_set_fmpz(u, n1); ok = (qqbar_cmp_re(u, x) < 0 && qqbar_cmp_re(x, t) <= 0); if (!ok) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("n = "); fmpz_print(n); flint_printf("\n\n"); flint_printf("n1 = "); fmpz_print(n1); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(t); qqbar_clear(u); fmpz_clear(n); fmpz_clear(n1); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-cmp_im.c000066400000000000000000000035221407704557200171040ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("cmp_im...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, xr, yr, t, u; int c1, c2; qqbar_init(x); qqbar_init(y); qqbar_init(xr); qqbar_init(yr); qqbar_init(t); qqbar_init(u); qqbar_randtest(x, state, 3, 100); if (n_randint(state, 2)) qqbar_set(y, x); else qqbar_randtest(y, state, 3, 10); if (n_randint(state, 2)) qqbar_conj(y, y); qqbar_randtest_real(t, state, 1, 100); qqbar_i(u); qqbar_mul(t, t, u); qqbar_add(x, x, t); qqbar_im(xr, x); qqbar_im(yr, y); c1 = qqbar_cmp_im(x, y); c2 = qqbar_cmp_re(xr, yr); if (c1 != c2) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("%d\n\n", c1); flint_printf("%d\n\n", c2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(xr); qqbar_clear(yr); qqbar_clear(t); qqbar_clear(u); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-cmp_re.c000066400000000000000000000035531407704557200171110ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("cmp_re...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, xr, yr, t, u; int c1, c2; qqbar_init(x); qqbar_init(y); qqbar_init(xr); qqbar_init(yr); qqbar_init(t); qqbar_init(u); qqbar_randtest(x, state, 3, 100); if (n_randint(state, 2)) qqbar_set(y, x); else qqbar_randtest(y, state, 3, 10); if (n_randint(state, 2)) qqbar_conj(y, y); qqbar_randtest_real(t, state, 1, 100); qqbar_i(u); qqbar_mul(t, t, u); qqbar_add(x, x, t); qqbar_re(xr, x); qqbar_re(yr, y); qqbar_sub(t, xr, yr); c1 = qqbar_cmp_re(x, y); c2 = qqbar_sgn_re(t); if (c1 != c2) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("%d\n\n", c1); flint_printf("%d\n\n", c2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(xr); qqbar_clear(yr); qqbar_clear(t); qqbar_clear(u); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-cmpabs.c000066400000000000000000000031731407704557200171070ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("cmpabs...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, xr, yr; int c1, c2; qqbar_init(x); qqbar_init(y); qqbar_init(xr); qqbar_init(yr); qqbar_randtest(x, state, 3, 100); qqbar_randtest(y, state, 3, 100); qqbar_abs(xr, x); qqbar_abs(yr, y); c1 = qqbar_cmpabs(x, y); c2 = qqbar_cmp_re(xr, yr); if (c1 != c2) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("xr = "); qqbar_print(xr); flint_printf("\n\n"); flint_printf("yr = "); qqbar_print(yr); flint_printf("\n\n"); flint_printf("%d\n\n", c1); flint_printf("%d\n\n", c2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(xr); qqbar_clear(yr); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-cmpabs_im.c000066400000000000000000000036671407704557200176040ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("cmpabs_im...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, xr, yr, z, i; int c1, c2; qqbar_init(x); qqbar_init(y); qqbar_init(xr); qqbar_init(yr); qqbar_init(z); qqbar_init(i); qqbar_randtest(x, state, 3, 100); if (n_randint(state, 4) == 0) qqbar_conj(y, x); else qqbar_randtest(y, state, 3, 100); qqbar_im(xr, x); qqbar_im(yr, y); qqbar_abs(xr, xr); qqbar_abs(yr, yr); if (n_randint(state, 2)) { qqbar_i(i); qqbar_randtest(z, state, 1, 100); qqbar_mul(z, z, i); qqbar_add(x, x, z); qqbar_sub(x, x, z); } c1 = qqbar_cmpabs_im(x, y); c2 = qqbar_cmp_re(xr, yr); if (c1 != c2) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("%d\n\n", c1); flint_printf("%d\n\n", c2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(xr); qqbar_clear(yr); qqbar_clear(z); qqbar_clear(i); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-cmpabs_re.c000066400000000000000000000034311407704557200175720ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("cmpabs_re...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, xr, yr, z; int c1, c2; qqbar_init(x); qqbar_init(y); qqbar_init(xr); qqbar_init(yr); qqbar_init(z); qqbar_randtest(x, state, 3, 100); qqbar_randtest(y, state, 3, 100); qqbar_re(xr, x); qqbar_re(yr, y); qqbar_abs(xr, xr); qqbar_abs(yr, yr); qqbar_randtest(z, state, 1, 100); qqbar_add(x, x, z); qqbar_sub(x, x, z); qqbar_randtest(z, state, 1, 100); qqbar_add(y, y, z); qqbar_sub(y, y, z); c1 = qqbar_cmpabs_re(x, y); c2 = qqbar_cmp_re(xr, yr); if (c1 != c2) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("%d\n\n", c1); flint_printf("%d\n\n", c2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(xr); qqbar_clear(yr); qqbar_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-conjugates.c000066400000000000000000000035061407704557200200040ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("conjugates...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z; qqbar_ptr r; fmpq_t s; slong i, d; qqbar_init(x); qqbar_init(y); qqbar_init(z); fmpq_init(s); qqbar_randtest(x, state, 4, 10); d = qqbar_degree(x); r = _qqbar_vec_init(d); qqbar_conjugates(r, x); for (i = 0; i < d; i++) qqbar_add(y, y, r + i); fmpq_set_fmpz_frac(s, QQBAR_COEFFS(x) + d - 1, QQBAR_COEFFS(x) + d); fmpq_neg(s, s); qqbar_set_fmpq(z, s); if (!qqbar_equal(y, z)) { flint_printf("FAIL! %d\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); for (i = 0; i < d; i++) { flint_printf("r%wd = ", i); qqbar_print(r + i); flint_printf("\n\n"); } flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); _qqbar_vec_clear(r, d); fmpq_clear(s); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-cos_pi.c000066400000000000000000000032351407704557200171150ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("cos_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x; arb_t z, w; fmpq_t t; slong p; ulong q; slong prec; qqbar_init(x); arb_init(z); arb_init(w); fmpq_init(t); q = 1 + n_randint(state, 30); p = n_randint(state, 1000); p -= 500; prec = 2 + n_randint(state, 1000); qqbar_cos_pi(x, p, q); qqbar_get_arb(z, x, prec); fmpq_set_si(t, p, q); arb_cos_pi_fmpq(w, t, prec); if (!arb_overlaps(z, w)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("z = "); arb_printn(z, 200, 0); flint_printf("\n\n"); flint_printf("w = "); arb_printn(w, 200, 0); flint_printf("\n\n"); flint_printf("p, q = %wd %wu\n\n", p, q); flint_abort(); } qqbar_clear(x); arb_clear(z); arb_clear(w); fmpq_clear(t); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-cot_pi.c000066400000000000000000000034771407704557200171260ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("cot_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { qqbar_t x; arb_t z, w; fmpq_t t; slong p; ulong q; slong prec; qqbar_init(x); arb_init(z); arb_init(w); fmpq_init(t); q = 1 + n_randint(state, 20); p = n_randint(state, 1000); p -= 500; prec = 2 + n_randint(state, 1000); fmpq_set_si(t, p, q); arb_sin_pi_fmpq(w, t, prec); arb_cos_pi_fmpq(z, t, prec); arb_div(w, z, w, prec); if (arb_is_finite(w)) { qqbar_cot_pi(x, p, q); qqbar_get_arb(z, x, prec); if (!arb_overlaps(z, w)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("z = "); arb_printn(z, 200, 0); flint_printf("\n\n"); flint_printf("w = "); arb_printn(w, 200, 0); flint_printf("\n\n"); flint_printf("p, q = %wd %wu\n\n", p, q); flint_abort(); } } qqbar_clear(x); arb_clear(z); arb_clear(w); fmpq_clear(t); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-csc_pi.c000066400000000000000000000034271407704557200171040ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("csc_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { qqbar_t x; arb_t z, w; fmpq_t t; slong p; ulong q; slong prec; qqbar_init(x); arb_init(z); arb_init(w); fmpq_init(t); q = 1 + n_randint(state, 20); p = n_randint(state, 1000); p -= 500; prec = 2 + n_randint(state, 1000); fmpq_set_si(t, p, q); arb_sin_pi_fmpq(w, t, prec); arb_inv(w, w, prec); if (arb_is_finite(w)) { qqbar_csc_pi(x, p, q); qqbar_get_arb(z, x, prec); if (!arb_overlaps(z, w)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("z = "); arb_printn(z, 200, 0); flint_printf("\n\n"); flint_printf("w = "); arb_printn(w, 200, 0); flint_printf("\n\n"); flint_printf("p, q = %wd %wu\n\n", p, q); flint_abort(); } } qqbar_clear(x); arb_clear(z); arb_clear(w); fmpq_clear(t); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-csgn.c000066400000000000000000000027471407704557200166020ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("csgn...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 500 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_randtest(x, state, 4, 8); qqbar_set_si(y, qqbar_csgn(x)); if (qqbar_is_zero(x)) { qqbar_zero(z); } else { qqbar_sqr(z, x); qqbar_sqrt(z, z); qqbar_div(z, z, x); } if (!qqbar_equal(y, z)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-div.c000066400000000000000000000134621407704557200164260ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("div...."); fflush(stdout); flint_randinit(state); /* Check division with degree-1 terms, large coefficients */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); do { qqbar_randtest(x, state, 20, 100); } while (qqbar_is_zero(x)); do { qqbar_randtest(y, state, 1, 100); } while (qqbar_is_zero(y)); qqbar_randtest(z, state, 1, 100); /* check z / (x / y) = (z / x) * y */ qqbar_div(a, x, y); qqbar_div(a, z, a); qqbar_div(b, z, x); qqbar_mul(b, b, y); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* Check division with degree-1 terms, small coefficients */ for (iter = 0; iter < 100; iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); do { qqbar_randtest(x, state, 30, 10); } while (qqbar_is_zero(x)); do { qqbar_randtest(y, state, 1, 10); } while (qqbar_is_zero(y)); qqbar_randtest(z, state, 1, 10); /* check z / (x / y) = (z / x) * y */ qqbar_div(a, x, y); qqbar_div(a, z, a); qqbar_div(b, z, x); qqbar_mul(b, b, y); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* Check division with higher-degree terms */ for (iter = 0; iter < 100; iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); do { qqbar_randtest(x, state, 6, 10); } while (qqbar_is_zero(x)); do { qqbar_randtest(y, state, 6, 10); } while (qqbar_is_zero(y)); qqbar_randtest(z, state, 2, 10); /* check z / (x / y) = (z / x) * y */ qqbar_div(a, x, y); qqbar_div(a, z, a); qqbar_div(b, z, x); qqbar_mul(b, b, y); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* Check roots of rational numbers, which are special-cased. */ for (iter = 0; iter < 100; iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); do { qqbar_randtest(x, state, 1, 10); } while (qqbar_is_zero(x)); qqbar_pow_ui(x, x, 1 + n_randint(state, 3)); qqbar_abs(x, x); qqbar_root_ui(x, x, 1 + n_randint(state, 10)); do { qqbar_randtest(y, state, 1, 10); } while (qqbar_is_zero(y)); qqbar_pow_ui(y, y, 1 + n_randint(state, 3)); qqbar_abs(y, y); qqbar_root_ui(y, y, 1 + n_randint(state, 10)); qqbar_randtest(z, state, 2, 10); /* check z / (x / y) = (z / x) * y */ qqbar_div(a, x, y); qqbar_div(a, z, a); qqbar_div(b, z, x); qqbar_mul(b, b, y); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-equal_fmpq_poly_val.c000066400000000000000000000046321407704557200217020ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int qqbar_equal_fmpq_poly_val2(const qqbar_t x, const fmpq_poly_t f, const qqbar_t y) { int found; qqbar_t v; qqbar_init(v); qqbar_evaluate_fmpq_poly(v, f, y); found = qqbar_equal(v, x); qqbar_clear(v); return found; } int main() { slong iter; flint_rand_t state; flint_printf("equal_fmpq_poly_val...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; qqbar_ptr v; fmpq_poly_t f; int equal1, equal2; slong d; qqbar_init(x); qqbar_init(y); fmpq_poly_init(f); if (n_randint(state, 2)) qqbar_randtest(y, state, 4, 10); else qqbar_randtest(y, state, 2, 100); do { fmpq_poly_randtest(f, state, 10, 10); } while (f->length == 0); switch (n_randint(state, 3)) { case 0: qqbar_randtest(x, state, 4, 20); break; case 1: qqbar_evaluate_fmpq_poly(x, f, y); break; default: qqbar_evaluate_fmpq_poly(x, f, y); d = qqbar_degree(x); v = _qqbar_vec_init(d); qqbar_conjugates(v, x); qqbar_set(x, v + n_randint(state, d)); _qqbar_vec_clear(v, d); } equal1 = qqbar_equal_fmpq_poly_val(x, f, y); equal2 = qqbar_equal_fmpq_poly_val2(x, f, y); if (equal1 != equal2) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("f = "); fmpq_poly_print(f); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); fmpq_poly_clear(f); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-evaluate_fmpq_poly.c000066400000000000000000000043671407704557200215440ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("evaluate_fmpq_poly...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { fmpq_poly_t f, g, h; qqbar_t x, fx, gx, hx, y; fmpq_poly_init(f); fmpq_poly_init(g); fmpq_poly_init(h); qqbar_init(x); qqbar_init(fx); qqbar_init(gx); qqbar_init(hx); qqbar_init(y); qqbar_randtest(x, state, 4, 10); qqbar_randtest(y, state, 4, 10); fmpq_poly_randtest(f, state, 8, 10); fmpq_poly_randtest(g, state, 5, 10); fmpq_poly_add(h, f, g); qqbar_evaluate_fmpq_poly(fx, f, x); qqbar_evaluate_fmpq_poly(gx, g, x); qqbar_evaluate_fmpq_poly(hx, h, x); qqbar_add(y, fx, gx); if (!qqbar_equal(y, hx)) { flint_printf("FAIL!\n"); flint_printf("f = "); fmpq_poly_print(f); flint_printf("\n\n"); flint_printf("g = "); fmpq_poly_print(g); flint_printf("\n\n"); flint_printf("h = "); fmpq_poly_print(h); flint_printf("\n\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("fx = "); qqbar_print(fx); flint_printf("\n\n"); flint_printf("gx = "); qqbar_print(gx); flint_printf("\n\n"); flint_printf("hx = "); qqbar_print(hx); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_abort(); } fmpq_poly_clear(f); fmpq_poly_clear(g); fmpq_poly_clear(h); qqbar_clear(x); qqbar_clear(fx); qqbar_clear(gx); qqbar_clear(hx); qqbar_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-evaluate_fmpz_mpoly.c000066400000000000000000000055571407704557200217340ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("evaluate_fmpz_mpoly...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { slong i, n; fmpz_mpoly_ctx_t ctx; fmpz_mpoly_t f, g, h; qqbar_ptr x; qqbar_t fx, gx, hx, y; int s1, s2, s3; n = 1 + n_randint(state, 5); fmpz_mpoly_ctx_init(ctx, n, ORD_LEX); fmpz_mpoly_init(f, ctx); fmpz_mpoly_init(g, ctx); fmpz_mpoly_init(h, ctx); x = _qqbar_vec_init(n); qqbar_init(fx); qqbar_init(gx); qqbar_init(hx); qqbar_init(y); for (i = 0; i < n; i++) qqbar_randtest(x + i, state, 1 + n_randint(state, 2), 10); fmpz_mpoly_randtest_bound(f, state, 1 + n_randint(state, 30), 10, 1 + n_randint(state, 4), ctx); fmpz_mpoly_randtest_bound(g, state, 1 + n_randint(state, 30), 10, 1 + n_randint(state, 4), ctx); fmpz_mpoly_add(h, f, g, ctx); s1 = qqbar_evaluate_fmpz_mpoly(fx, f, x, 40, 1000, ctx); s2 = qqbar_evaluate_fmpz_mpoly(gx, g, x, 40, 1000, ctx); s3 = qqbar_evaluate_fmpz_mpoly(hx, h, x, 40, 1000, ctx); qqbar_add(y, fx, gx); if (s1 && s2 && s3 && !qqbar_equal(y, hx)) { flint_printf("FAIL!\n"); flint_printf("f = "); fmpz_mpoly_print_pretty(f, NULL, ctx); flint_printf("\n\n"); flint_printf("g = "); fmpz_mpoly_print_pretty(g, NULL, ctx); flint_printf("\n\n"); flint_printf("h = "); fmpz_mpoly_print_pretty(h, NULL, ctx); flint_printf("\n\n"); for (i = 0; i < n; i++) { flint_printf("x%wd = ", i + 1); qqbar_print(x + i); flint_printf("\n\n"); } flint_printf("fx = "); qqbar_print(fx); flint_printf("\n\n"); flint_printf("gx = "); qqbar_print(gx); flint_printf("\n\n"); flint_printf("hx = "); qqbar_print(hx); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_abort(); } fmpz_mpoly_clear(f, ctx); fmpz_mpoly_clear(g, ctx); fmpz_mpoly_clear(h, ctx); fmpz_mpoly_ctx_clear(ctx); _qqbar_vec_clear(x, n); qqbar_clear(fx); qqbar_clear(gx); qqbar_clear(hx); qqbar_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-exp_pi_i.c000066400000000000000000000033011407704557200174270ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("exp_pi_i...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { qqbar_t x; acb_t z, w; fmpq_t t; slong p; ulong q; slong prec; qqbar_init(x); acb_init(z); acb_init(w); fmpq_init(t); q = 1 + n_randint(state, 20); p = n_randint(state, 1000); p -= 500; prec = 2 + n_randint(state, 1000); fmpq_set_si(t, p, q); arb_sin_cos_pi_fmpq(acb_imagref(w), acb_realref(w), t, prec); qqbar_exp_pi_i(x, p, q); qqbar_get_acb(z, x, prec); if (!acb_overlaps(z, w)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("z = "); acb_printn(z, 200, 0); flint_printf("\n\n"); flint_printf("w = "); acb_printn(w, 200, 0); flint_printf("\n\n"); flint_printf("p, q = %wd %wu\n\n", p, q); flint_abort(); } qqbar_clear(x); acb_clear(z); acb_clear(w); fmpq_clear(t); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-express_in_field.c000066400000000000000000000042731407704557200211660ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("express_in_field...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { fmpq_poly_t f, g; qqbar_t x, alpha; slong prec, max_bits; fmpq_poly_init(f); fmpq_poly_init(g); qqbar_init(x); qqbar_init(alpha); if (n_randint(state, 2)) qqbar_randtest(alpha, state, 4, 100); else qqbar_randtest(alpha, state, 6, 10); if (n_randint(state, 4) == 0) fmpq_poly_randtest(f, state, qqbar_degree(alpha), 100); else fmpq_poly_randtest(f, state, qqbar_degree(alpha), 8); max_bits = _fmpz_vec_max_bits(f->coeffs, f->length); max_bits = FLINT_ABS(max_bits); max_bits = FLINT_MAX(max_bits, fmpz_bits(f->den)); qqbar_evaluate_fmpq_poly(x, f, alpha); for (prec = 64; ; prec *= 2) { if (qqbar_express_in_field(g, alpha, x, max_bits, 0, prec)) break; if (prec > 10000) { flint_printf("FAIL!\n"); flint_printf("alpha = "); qqbar_print(alpha); flint_printf("\n\n"); flint_printf("f = "); fmpq_poly_print(f); flint_printf("\n\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("g = "); fmpq_poly_print(g); flint_printf("\n\n"); flint_printf("prec = %wd\n\n", prec); flint_abort(); } } fmpq_poly_clear(f); fmpq_poly_clear(g); qqbar_clear(alpha); qqbar_clear(x); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-floor.c000066400000000000000000000040711407704557200167610ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("floor...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, t, u; fmpz_t n, n1; int ok; qqbar_init(x); qqbar_init(y); qqbar_init(t); qqbar_init(u); fmpz_init(n); fmpz_init(n1); if (n_randint(state, 2)) { qqbar_randtest(x, state, 4, 200); } else { fmpq_t c; fmpq_init(c); fmpz_randtest(n, state, 400); fmpq_randtest(c, state, 400); fmpq_add_fmpz(c, c, n); fmpz_zero(n); qqbar_set_fmpq(x, c); qqbar_randtest(y, state, 1, 100); qqbar_i(t); qqbar_mul(y, y, t); qqbar_add(x, x, y); fmpq_clear(c); } qqbar_floor(n, x); fmpz_add_ui(n1, n, 1); qqbar_set_fmpz(t, n); qqbar_set_fmpz(u, n1); ok = (qqbar_cmp_re(t, x) <= 0 && qqbar_cmp_re(x, u) < 0); if (!ok) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("n = "); fmpz_print(n); flint_printf("\n\n"); flint_printf("n1 = "); fmpz_print(n1); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(t); qqbar_clear(u); fmpz_clear(n); fmpz_clear(n1); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-fmpz_poly_composed_op.c000066400000000000000000000067031407704557200222520ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("fmpz_poly_composed_op...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { slong m, n, i, j, k; fmpz *r1, *r2; fmpz_poly_t A, B, C; fmpq_t x, y; int op; m = 1 + n_randint(state, 8); n = 1 + n_randint(state, 8); op = n_randint(state, 4); i = n_randint(state, m); j = n_randint(state, n); op = n_randint(state, 4); r1 = _fmpz_vec_init(m); r2 = _fmpz_vec_init(n); fmpz_poly_init(A); fmpz_poly_init(B); fmpz_poly_init(C); fmpq_init(x); fmpq_init(y); _fmpz_vec_randtest(r1, state, m, 10); _fmpz_vec_randtest(r2, state, n, 10); /* Don't divide by zero */ if (op == 3) { for (k = 0; k < n; k++) { if (fmpz_is_zero(r2 + k)) fmpz_one(r2 + k); } } fmpz_poly_product_roots_fmpz_vec(A, r1, m); fmpz_poly_product_roots_fmpz_vec(B, r2, n); if (n_randint(state, 2)) { fmpz_randtest_not_zero(fmpq_numref(x), state, 10); fmpz_poly_scalar_mul_fmpz(A, A, fmpq_numref(x)); fmpz_randtest_not_zero(fmpq_numref(x), state, 10); fmpz_poly_scalar_mul_fmpz(B, B, fmpq_numref(x)); } /* output noise */ fmpz_poly_randtest(C, state, 10, 100); qqbar_fmpz_poly_composed_op(C, A, B, op); if (op == 0) { fmpz_add(fmpq_numref(x), r1 + i, r2 + j); fmpz_one(fmpq_denref(x)); } else if (op == 1) { fmpz_sub(fmpq_numref(x), r1 + i, r2 + j); fmpz_one(fmpq_denref(x)); } else if (op == 2) { fmpz_mul(fmpq_numref(x), r1 + i, r2 + j); fmpz_one(fmpq_denref(x)); } else { fmpq_set_fmpz_frac(x, r1 + i, r2 + j); } fmpz_poly_evaluate_fmpq(y, C, x); if (!fmpq_is_zero(y)) { flint_printf("FAIL!\n"); flint_printf("op = %d\n", op); flint_printf("A = "); fmpz_poly_print(A); flint_printf("\n\n"); flint_printf("B = "); fmpz_poly_print(B); flint_printf("\n\n"); flint_printf("C = "); fmpz_poly_print(C); flint_printf("\n\n"); flint_printf("r1 = "); fmpz_print(r1 + i); flint_printf("\n\n"); flint_printf("r2 = "); fmpz_print(r2 + j); flint_printf("\n\n"); flint_printf("x = "); fmpq_print(x); flint_printf("\n\n"); flint_printf("y = "); fmpq_print(y); flint_printf("\n\n"); flint_abort(); } _fmpz_vec_clear(r1, m); _fmpz_vec_clear(r2, n); fmpz_poly_clear(A); fmpz_poly_clear(B); fmpz_poly_clear(C); fmpq_clear(x); fmpq_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-get_acb.c000066400000000000000000000061211407704557200172220ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("get_acb...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x; acb_t z, w; slong prec1, prec2, acc1, acc2; qqbar_init(x); acb_init(z); acb_init(w); qqbar_randtest(x, state, 3, 400); prec1 = 2 + n_randint(state, 800); prec2 = prec1 + 2 + n_randint(state, 400); qqbar_get_acb(z, x, prec1); qqbar_get_acb(w, x, prec2); acc1 = arb_rel_accuracy_bits(acb_realref(z)); acc2 = arb_rel_accuracy_bits(acb_imagref(z)); if (acc1 < prec1 - 2 || acc2 < prec1 - 2) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("z = "); acb_printn(z, 1000, ARB_STR_CONDENSE * 30); flint_printf("\n\n"); flint_printf("prec1 = %wd, acc1 = %wd, acc2 = %wd\n\n", prec1, acc1, acc2); flint_abort(); } acc1 = arb_rel_accuracy_bits(acb_realref(w)); acc2 = arb_rel_accuracy_bits(acb_imagref(w)); if (acc1 < prec2 - 2 || acc2 < prec2 - 2) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("w = "); acb_printn(w, 1000, ARB_STR_CONDENSE * 30); flint_printf("\n\n"); flint_printf("prec2 = %wd, acc1 = %wd, acc2 = %wd\n\n", prec2, acc1, acc2); flint_abort(); } if (!acb_overlaps(z, w)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("z re = "); arb_printn(acb_realref(z), 1000, 0); flint_printf("\n\n"); flint_printf("z im = "); arb_printn(acb_imagref(z), 1000, 0); flint_printf("\n\n"); flint_printf("w re = "); arb_printn(acb_realref(w), 1000, 0); flint_printf("\n\n"); flint_printf("w im = "); arb_printn(acb_imagref(w), 1000, 0); flint_printf("\n\n"); flint_printf("z re = "); arb_print(acb_realref(z)); flint_printf("\n\n"); flint_printf("z im = "); arb_print(acb_imagref(z)); flint_printf("\n\n"); flint_printf("w re = "); arb_print(acb_realref(w)); flint_printf("\n\n"); flint_printf("w im = "); arb_print(acb_imagref(w)); flint_printf("\n\n"); flint_printf("prec1 = %wd, prec2 = %wd\n\n", prec1, prec2); flint_abort(); } qqbar_clear(x); acb_clear(z); acb_clear(w); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-get_fexpr.c000066400000000000000000000051711407704557200176250ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("get_fexpr...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; fexpr_t e; qqbar_init(x); qqbar_init(y); fexpr_init(e); if (n_randint(state, 2)) qqbar_randtest(x, state, 2, 10); else if (n_randint(state, 2)) qqbar_randtest(x, state, 5, 100); else qqbar_randtest(x, state, 20, 20); qqbar_get_fexpr_repr(e, x); if (!qqbar_set_fexpr(y, e) || !qqbar_equal(x, y)) { flint_printf("FAIL! (repr)\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("e = "); fexpr_print(e); flint_printf("\n\n"); flint_abort(); } qqbar_get_fexpr_root_indexed(e, x); qqbar_zero(y); if (!qqbar_set_fexpr(y, e) || !qqbar_equal(x, y)) { flint_printf("FAIL! (root_indexed)\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("e = "); fexpr_print(e); flint_printf("\n\n"); flint_abort(); } /* flint_printf("%wd\n", iter); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); */ qqbar_get_fexpr_root_nearest(e, x); qqbar_zero(y); /* flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("e = "); fexpr_print(e); flint_printf("\n\n"); */ if (!qqbar_set_fexpr(y, e) || !qqbar_equal(x, y)) { flint_printf("FAIL! (root_nearest)\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("e = "); fexpr_print(e); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); fexpr_clear(e); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-get_fexpr_formula.c000066400000000000000000000076161407704557200213600ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("get_fexpr_formula...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; fexpr_t e; ulong flags; qqbar_init(x); qqbar_init(y); fexpr_init(e); qqbar_randtest(x, state, 5, 10); if (n_randint(state, 2)) flags = n_randlimb(state); else flags = QQBAR_FORMULA_ALL; if (qqbar_get_fexpr_formula(e, x, flags)) { qqbar_set_fexpr(y, e); if (!qqbar_equal(x, y)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("e = "); fexpr_print(e); flint_printf("\n\n"); flint_abort(); } } qqbar_clear(x); qqbar_clear(y); fexpr_clear(e); } /* test trigonometrics and exponentials */ for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; fexpr_t e; slong p, q; fmpq_t a; qqbar_init(x); qqbar_init(y); fexpr_init(e); fmpq_init(a); p = -10 + n_randint(state, 100); if (n_randint(state, 10)) q = 1 + n_randint(state, 6); else q = 1 + n_randint(state, 10); switch (n_randint(state, 7)) { case 0: qqbar_exp_pi_i(x, p, q); break; case 1: qqbar_sin_pi(x, p, q); break; case 2: qqbar_cos_pi(x, p, q); break; case 3: qqbar_tan_pi(x, p, q); break; case 4: qqbar_cot_pi(x, p, q); break; case 5: qqbar_sec_pi(x, p, q); break; case 6: qqbar_csc_pi(x, p, q); break; } fmpq_randtest(a, state, 3); qqbar_add_fmpq(x, x, a); fmpq_randtest(a, state, 3); qqbar_mul_fmpq(x, x, a); if (qqbar_degree(x) <= 2) { p = -10 + n_randint(state, 100); q = 1 + n_randint(state, 6); switch (n_randint(state, 7)) { case 0: qqbar_exp_pi_i(y, p, q); break; case 1: qqbar_sin_pi(y, p, q); break; case 2: qqbar_cos_pi(y, p, q); break; case 3: qqbar_tan_pi(y, p, q); break; case 4: qqbar_cot_pi(y, p, q); break; case 5: qqbar_sec_pi(y, p, q); break; case 6: qqbar_csc_pi(y, p, q); break; } qqbar_add(x, x, y); qqbar_zero(y); } if (qqbar_get_fexpr_formula(e, x, QQBAR_FORMULA_ALL)) { qqbar_set_fexpr(y, e); if (!qqbar_equal(x, y)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("e = "); fexpr_print(e); flint_printf("\n\n"); flint_abort(); } } else { flint_printf("Unexpected:\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); } qqbar_clear(x); qqbar_clear(y); fexpr_clear(e); fmpq_clear(a); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-get_quadratic.c000066400000000000000000000057551407704557200204660ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("get_quadratic...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; fmpz_t a, b, c, q, d, n; qqbar_init(x); qqbar_init(y); fmpz_init(a); fmpz_init(b); fmpz_init(c); fmpz_init(q); fmpz_init(d); fmpz_init(n); switch (n_randint(state, 3)) { case 0: qqbar_randtest(x, state, 2, 2 + n_randint(state, 20)); qqbar_get_quadratic(a, b, c, q, x, 1); break; case 1: qqbar_randtest(x, state, 2, 2 + n_randint(state, 40)); qqbar_get_quadratic(a, b, c, q, x, 2); break; default: qqbar_randtest(x, state, 2, 2 + n_randint(state, 80)); qqbar_get_quadratic(a, b, c, q, x, 0); break; } qqbar_set_fmpz(y, c); qqbar_sqrt(y, y); qqbar_mul_fmpz(y, y, b); qqbar_add_fmpz(y, y, a); qqbar_div_fmpz(y, y, q); if (!qqbar_equal(x, y)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("a = "); fmpz_print(a); flint_printf("\n\n"); flint_printf("b = "); fmpz_print(b); flint_printf("\n\n"); flint_printf("c = "); fmpz_print(c); flint_printf("\n\n"); flint_printf("q = "); fmpz_print(q); flint_printf("\n\n"); flint_abort(); } fmpz_gcd(d, a, b); fmpz_gcd(d, d, q); if (!fmpz_is_one(d) || fmpz_sgn(q) < 0 || (qqbar_degree(x) == 2 && (fmpz_is_square(c) || fmpz_val2(c) >= 2))) { flint_printf("FAIL (normalization)\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("a = "); fmpz_print(a); flint_printf("\n\n"); flint_printf("b = "); fmpz_print(b); flint_printf("\n\n"); flint_printf("c = "); fmpz_print(c); flint_printf("\n\n"); flint_printf("q = "); fmpz_print(q); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); fmpz_clear(a); fmpz_clear(b); fmpz_clear(c); fmpz_clear(q); fmpz_clear(d); fmpz_clear(n); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-guess.c000066400000000000000000000032101407704557200167600ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("guess...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { qqbar_t x, y; acb_t z; slong prec, max_deg, max_bits; qqbar_init(x); qqbar_init(y); acb_init(z); if (n_randint(state, 2)) qqbar_randtest(x, state, 4, 100); else qqbar_randtest(x, state, 12, 10); max_deg = qqbar_degree(x) + n_randint(state, 2); max_bits = qqbar_height_bits(x) + n_randint(state, 100); for (prec = 64; ; prec *= 2) { qqbar_get_acb(z, x, prec); if (qqbar_guess(y, z, max_deg, max_bits, 0, prec) && qqbar_equal(x, y)) break; if (prec > 10000) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("prec = %wd\n\n", prec); flint_abort(); } } qqbar_clear(x); qqbar_clear(y); acb_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-inv.c000066400000000000000000000025641407704557200164410ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("inv...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z; qqbar_init(x); qqbar_init(y); qqbar_init(z); do { qqbar_randtest(x, state, 8, 2 + n_randint(state, 100)); } while (qqbar_is_zero(x)); qqbar_inv(y, x); qqbar_inv(z, y); if (!qqbar_equal(x, z)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-log_pi_i.c000066400000000000000000000031471407704557200174240ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("log_pi_i...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; slong p, p2; ulong q, q2; int res; qqbar_init(x); qqbar_init(y); q = 1 + n_randint(state, 30); p = n_randint(state, 1000); p -= 500; qqbar_exp_pi_i(x, p, q); res = qqbar_log_pi_i(&p2, &q2, x); if (res) qqbar_exp_pi_i(y, p2, q2); if (res == 0 || !qqbar_equal(x, y) || n_gcd(FLINT_ABS(p2), q2) != 1 || p2 > (slong) q2 || p2 <= -(slong) q2) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("res = %d\n\n", res); flint_printf("p, p2 = %wd %wd\n\n", p, p2); flint_printf("q, q2 = %wu %wu\n\n", q, q2); flint_abort(); } qqbar_clear(x); qqbar_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-mul.c000066400000000000000000000152711407704557200164410ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("mul...."); fflush(stdout); flint_randinit(state); /* Check multiplication with degree-1 terms, large coefficients */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 20, 100); qqbar_randtest(y, state, 1, 100); qqbar_randtest(z, state, 1, 100); /* check (x * y) * z = x * (y * z) */ qqbar_mul(a, x, y); qqbar_mul(a, a, z); qqbar_mul(b, y, z); qqbar_mul(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* Check multiplication with degree-1 terms, small coefficients */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 30, 10); qqbar_randtest(y, state, 1, 10); qqbar_randtest(z, state, 1, 10); /* check (x * y) * z = x * (y * z) */ qqbar_mul(a, x, y); qqbar_mul(a, a, z); qqbar_mul(b, y, z); qqbar_mul(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* Check multiplication with higher-degree terms */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 6, 10); qqbar_randtest(y, state, 6, 10); qqbar_randtest(z, state, 2, 10); /* check (x * y) * z = x * (y * z) */ qqbar_mul(a, x, y); qqbar_mul(a, a, z); qqbar_mul(b, y, z); qqbar_mul(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* More iterations, low degree */ for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 4, 10); qqbar_randtest(y, state, 3, 10); qqbar_randtest(z, state, 2, 10); /* check (x * y) * z = x * (y * z) */ qqbar_mul(a, x, y); qqbar_mul(a, a, z); qqbar_mul(b, y, z); qqbar_mul(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* Check roots of rational numbers, which are special-cased. */ for (iter = 0; iter < 100; iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); do { qqbar_randtest(x, state, 1, 10); } while (qqbar_is_zero(x)); qqbar_pow_ui(x, x, 1 + n_randint(state, 3)); qqbar_abs(x, x); qqbar_root_ui(x, x, 1 + n_randint(state, 10)); do { qqbar_randtest(y, state, 1, 10); } while (qqbar_is_zero(y)); qqbar_pow_ui(y, y, 1 + n_randint(state, 3)); qqbar_abs(y, y); qqbar_root_ui(y, y, 1 + n_randint(state, 10)); qqbar_randtest(z, state, 2, 10); /* check (x * y) * z = x * (y * z) */ qqbar_mul(a, x, y); qqbar_mul(a, a, z); qqbar_mul(b, y, z); qqbar_mul(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-mul_2exp_si.c000066400000000000000000000031551407704557200200700ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("mul_2exp_si...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z; slong e; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_randtest(x, state, 6, 10); e = n_randint(state, 100) - (slong) 50; if (n_randint(state, 2)) qqbar_mul_2exp_si(y, x, e); else { qqbar_set(y, x); qqbar_mul_2exp_si(y, y, e); } qqbar_one(z); qqbar_mul_2exp_si(z, z, e); qqbar_mul(z, z, x); if (!qqbar_equal(z, y)) { flint_printf("FAIL!\n"); flint_printf("%wd\n\n", e); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-pow.c000066400000000000000000000050151407704557200164440ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("pow...."); fflush(stdout); flint_randinit(state); /* Check x^m x^n = x^(m+n) */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, m, n, mn, xm, xn, xmxn, xmn; qqbar_init(x); qqbar_init(m); qqbar_init(n); qqbar_init(mn); qqbar_init(xm); qqbar_init(xn); qqbar_init(xmxn); qqbar_init(xmn); if (n_randint(state, 2)) { qqbar_root_of_unity(x, n_randint(state, 100), 1 + n_randint(state, 10)); qqbar_set_si(m, n_randtest(state)); qqbar_div_ui(m, m, 1 + n_randint(state, 5)); qqbar_set_si(n, n_randtest(state)); qqbar_div_ui(n, n, 1 + n_randint(state, 5)); } else { qqbar_randtest(x, state, 4, 10); qqbar_randtest(m, state, 4, 3); qqbar_randtest(n, state, 4, 3); } qqbar_add(mn, m, n); if (qqbar_pow(xm, x, m) && qqbar_pow(xn, x, n) && qqbar_pow(xmn, x, mn)) { qqbar_mul(xmxn, xm, xn); if (!qqbar_equal(xmxn, xmn)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("m = "); qqbar_print(m); flint_printf("\n\n"); flint_printf("n = "); qqbar_print(n); flint_printf("\n\n"); flint_printf("xm = "); qqbar_print(xm); flint_printf("\n\n"); flint_printf("xn = "); qqbar_print(xn); flint_printf("\n\n"); flint_printf("xmxn = "); qqbar_print(xmxn); flint_printf("\n\n"); flint_printf("xmn = "); qqbar_print(xmn); flint_printf("\n\n"); flint_abort(); } } qqbar_clear(x); qqbar_clear(m); qqbar_clear(n); qqbar_clear(mn); qqbar_clear(xm); qqbar_clear(xn); qqbar_clear(xmxn); qqbar_clear(xmn); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-pow_fmpq.c000066400000000000000000000050141407704557200174660ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("pow_fmpq...."); fflush(stdout); flint_randinit(state); /* Check x^m x^n = x^(m+n) */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, xm, xn, xmxn, xmn; fmpq_t m, n, mn; qqbar_init(x); qqbar_init(xm); qqbar_init(xn); qqbar_init(xmxn); qqbar_init(xmn); fmpq_init(m); fmpq_init(n); fmpq_init(mn); if (n_randint(state, 2)) { qqbar_root_of_unity(x, n_randint(state, 100), 1 + n_randint(state, 10)); fmpq_set_si(m, n_randtest(state), 1 + n_randint(state, 5)); fmpq_set_si(n, n_randtest(state), 1 + n_randint(state, 5)); } else { do { qqbar_randtest(x, state, 4, 10); fmpq_randtest(m, state, 3); fmpq_randtest(n, state, 3); } while (qqbar_is_zero(x) && (fmpq_sgn(m) < 0 || fmpq_sgn(n) < 0)); } fmpq_add(mn, m, n); qqbar_pow_fmpq(xm, x, m); qqbar_pow_fmpq(xn, x, n); qqbar_pow_fmpq(xmn, x, mn); qqbar_mul(xmxn, xm, xn); if (!qqbar_equal(xmxn, xmn)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("m = "); fmpq_print(m); flint_printf("\n\n"); flint_printf("n = "); fmpq_print(n); flint_printf("\n\n"); flint_printf("xm = "); qqbar_print(xm); flint_printf("\n\n"); flint_printf("xn = "); qqbar_print(xn); flint_printf("\n\n"); flint_printf("xmxn = "); qqbar_print(xmxn); flint_printf("\n\n"); flint_printf("xmn = "); qqbar_print(xmn); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(xm); qqbar_clear(xn); qqbar_clear(xmxn); qqbar_clear(xmn); fmpq_clear(m); fmpq_clear(n); fmpq_clear(mn); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-pow_fmpz.c000066400000000000000000000047321407704557200175050ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("pow_fmpz...."); fflush(stdout); flint_randinit(state); /* Check x^m x^n = x^(m+n) */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, xm, xn, xmxn, xmn; fmpz_t m, n, mn; qqbar_init(x); qqbar_init(xm); qqbar_init(xn); qqbar_init(xmxn); qqbar_init(xmn); fmpz_init(m); fmpz_init(n); fmpz_init(mn); if (n_randint(state, 2)) { qqbar_root_of_unity(x, n_randint(state, 100), 1 + n_randint(state, 10)); fmpz_set_si(m, n_randtest(state)); fmpz_set_si(n, n_randtest(state)); } else { do { qqbar_randtest(x, state, 4, 10); fmpz_randtest(m, state, 5); fmpz_randtest(n, state, 5); } while (qqbar_is_zero(x) && (fmpz_sgn(m) < 0 || fmpz_sgn(n) < 0)); } fmpz_add(mn, m, n); qqbar_pow_fmpz(xm, x, m); qqbar_pow_fmpz(xn, x, n); qqbar_pow_fmpz(xmn, x, mn); qqbar_mul(xmxn, xm, xn); if (!qqbar_equal(xmxn, xmn)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("m = "); fmpz_print(m); flint_printf("\n\n"); flint_printf("n = "); fmpz_print(n); flint_printf("\n\n"); flint_printf("xm = "); qqbar_print(xm); flint_printf("\n\n"); flint_printf("xn = "); qqbar_print(xn); flint_printf("\n\n"); flint_printf("xmxn = "); qqbar_print(xmxn); flint_printf("\n\n"); flint_printf("xmn = "); qqbar_print(xmn); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(xm); qqbar_clear(xn); qqbar_clear(xmxn); qqbar_clear(xmn); fmpz_clear(m); fmpz_clear(n); fmpz_clear(mn); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-pow_si.c000066400000000000000000000102251407704557200171360ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("pow_si...."); fflush(stdout); flint_randinit(state); /* Check x^m x^n = x^(m+n) */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, xm, xn, xmxn, xmn; slong m, n; qqbar_init(x); qqbar_init(xm); qqbar_init(xn); qqbar_init(xmxn); qqbar_init(xmn); if (n_randint(state, 2)) { qqbar_randtest(x, state, 4, 10); } else { /* check powers of rationals which are special-cased */ qqbar_randtest(x, state, 1, 10); qqbar_pow_ui(x, x, 1 + n_randint(state, 3)); qqbar_abs(x, x); qqbar_root_ui(x, x, 1 + n_randint(state, 10)); } m = n_randint(state, 7) - 4; n = n_randint(state, 7) - 4; while ((m < 0 || n < 0) && qqbar_is_zero(x)) qqbar_randtest(x, state, 2, 10); qqbar_pow_si(xm, x, m); qqbar_pow_si(xn, x, n); qqbar_mul(xmxn, xm, xn); qqbar_pow_si(xmn, x, m + n); if (!qqbar_equal(xmxn, xmn)) { flint_printf("FAIL!\n"); flint_printf("m = %wd\n\n", m); flint_printf("n = %wd\n\n", n); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("xm = "); qqbar_print(xm); flint_printf("\n\n"); flint_printf("xn = "); qqbar_print(xn); flint_printf("\n\n"); flint_printf("xmxn = "); qqbar_print(xmxn); flint_printf("\n\n"); flint_printf("xmn = "); qqbar_print(xmn); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(xm); qqbar_clear(xn); qqbar_clear(xmxn); qqbar_clear(xmn); } /* Check (xy)^n = x^n y^n */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, xyn, xn, yn, xnyn; slong n; qqbar_init(x); qqbar_init(y); qqbar_init(xyn); qqbar_init(xn); qqbar_init(yn); qqbar_init(xnyn); if (n_randint(state, 2)) { qqbar_randtest(x, state, 4, 10); } else { /* check powers of rationals which are special-cased */ qqbar_randtest(x, state, 1, 10); qqbar_pow_ui(x, x, 1 + n_randint(state, 3)); qqbar_abs(x, x); qqbar_root_ui(x, x, 1 + n_randint(state, 10)); } qqbar_randtest(y, state, 4, 10); n = n_randint(state, 7) - 4; while (n < 0 && qqbar_is_zero(x)) qqbar_randtest(x, state, 2, 10); while (n < 0 && qqbar_is_zero(y)) qqbar_randtest(y, state, 2, 10); qqbar_mul(xyn, x, y); qqbar_pow_si(xyn, xyn, n); qqbar_pow_si(xn, x, n); qqbar_pow_si(yn, y, n); qqbar_mul(xnyn, xn, yn); if (!qqbar_equal(xyn, xnyn)) { flint_printf("FAIL!\n"); flint_printf("n = %wd\n\n", n); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("xyn = "); qqbar_print(xyn); flint_printf("\n\n"); flint_printf("xn = "); qqbar_print(xn); flint_printf("\n\n"); flint_printf("yn = "); qqbar_print(yn); flint_printf("\n\n"); flint_printf("xnyn = "); qqbar_print(xnyn); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(xyn); qqbar_clear(xn); qqbar_clear(yn); qqbar_clear(xnyn); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-pow_ui.c000066400000000000000000000075661407704557200171560ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("pow_ui...."); fflush(stdout); flint_randinit(state); /* Check x^m x^n = x^(m+n) */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, xm, xn, xmxn, xmn; ulong m, n; qqbar_init(x); qqbar_init(xm); qqbar_init(xn); qqbar_init(xmxn); qqbar_init(xmn); if (n_randint(state, 2)) { qqbar_randtest(x, state, 4, 10); } else { /* check powers of rationals which are special-cased */ qqbar_randtest(x, state, 1, 10); qqbar_pow_ui(x, x, 1 + n_randint(state, 3)); qqbar_abs(x, x); qqbar_root_ui(x, x, 1 + n_randint(state, 10)); } m = n_randint(state, 7); n = n_randint(state, 7); qqbar_pow_ui(xm, x, m); qqbar_pow_ui(xn, x, n); qqbar_mul(xmxn, xm, xn); qqbar_pow_ui(xmn, x, m + n); if (!qqbar_equal(xmxn, xmn)) { flint_printf("FAIL!\n"); flint_printf("m = %wu\n\n", m); flint_printf("n = %wu\n\n", n); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("xm = "); qqbar_print(xm); flint_printf("\n\n"); flint_printf("xn = "); qqbar_print(xn); flint_printf("\n\n"); flint_printf("xmxn = "); qqbar_print(xmxn); flint_printf("\n\n"); flint_printf("xmn = "); qqbar_print(xmn); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(xm); qqbar_clear(xn); qqbar_clear(xmxn); qqbar_clear(xmn); } /* Check (xy)^n = x^n y^n */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, xyn, xn, yn, xnyn; ulong n; qqbar_init(x); qqbar_init(y); qqbar_init(xyn); qqbar_init(xn); qqbar_init(yn); qqbar_init(xnyn); if (n_randint(state, 2)) { qqbar_randtest(x, state, 4, 10); } else { /* check powers of rationals which are special-cased */ qqbar_randtest(x, state, 1, 10); qqbar_pow_ui(x, x, 1 + n_randint(state, 3)); qqbar_abs(x, x); qqbar_root_ui(x, x, 1 + n_randint(state, 10)); } qqbar_randtest(y, state, 4, 10); n = n_randint(state, 7); qqbar_mul(xyn, x, y); qqbar_pow_ui(xyn, xyn, n); qqbar_pow_ui(xn, x, n); qqbar_pow_ui(yn, y, n); qqbar_mul(xnyn, xn, yn); if (!qqbar_equal(xyn, xnyn)) { flint_printf("FAIL!\n"); flint_printf("n = %wu\n\n", n); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("xyn = "); qqbar_print(xyn); flint_printf("\n\n"); flint_printf("xn = "); qqbar_print(xn); flint_printf("\n\n"); flint_printf("yn = "); qqbar_print(yn); flint_printf("\n\n"); flint_printf("xnyn = "); qqbar_print(xnyn); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(xyn); qqbar_clear(xn); qqbar_clear(yn); qqbar_clear(xnyn); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-randtest.c000066400000000000000000000030611407704557200174620ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("randtest...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x; slong deg, bits; int real; qqbar_init(x); real = n_randint(state, 3); deg = 1 + n_randint(state, 4) + (real == 2); bits = 1 + n_randint(state, 4); if (real == 0) qqbar_randtest(x, state, deg, bits); else if (real == 1) qqbar_randtest_real(x, state, deg, bits); else if (real == 2) qqbar_randtest_nonreal(x, state, deg, bits); if (qqbar_degree(x) > deg || qqbar_height_bits(x) > bits || (real == 1 && !qqbar_is_real(x)) || (real == 2 && qqbar_is_real(x))) { flint_printf("FAIL\n"); flint_printf("deg = %wd, bits = %wd, real = %d\n", deg, bits, real); qqbar_print(x); flint_printf("\n"); flint_abort(); } qqbar_clear(x); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-re_im.c000066400000000000000000000032411407704557200167310ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("re_im...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, t; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(t); qqbar_randtest(x, state, 4, 10); qqbar_re(y, x); qqbar_im(z, x); if (n_randint(state, 2)) { qqbar_set_re_im(t, y, z); } else { qqbar_i(t); qqbar_mul(t, t, z); qqbar_add(t, t, y); } if (!qqbar_equal(t, x) || !qqbar_is_real(y) || !qqbar_is_real(z)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("t = "); qqbar_print(t); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(t); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-root_of_unity.c000066400000000000000000000040241407704557200205350ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("root_of_unity...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y; slong p, p2; ulong q, q2; int ok; qqbar_init(x); qqbar_init(y); q = 1 + n_randint(state, 30); p = n_randint(state, 1000); p -= 500; qqbar_root_of_unity(x, p, q); ok = qqbar_is_root_of_unity(&p2, &q2, x); qqbar_root_of_unity(y, p2, q2); if (!ok || !qqbar_equal(x, y) || n_gcd(FLINT_ABS(p2), q2) != 1 || !(0 <= p2 && p2 < (slong) 2 * q2)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("p, p2 = %wd %wd\n\n", p, p2); flint_printf("q, q2 = %wu %wu\n\n", q, q2); flint_abort(); } if (q <= 10) { qqbar_pow_ui(y, x, q); if (!qqbar_is_one(y)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("p, p2 = %wd %wd\n\n", p, p2); flint_printf("q, q2 = %wu %wu\n\n", q, q2); flint_abort(); } } qqbar_clear(x); qqbar_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-root_ui.c000066400000000000000000000041551407704557200173230ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("root_ui...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z; ulong n; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_randtest(x, state, 4, 10); /* generate noise */ qqbar_randtest(y, state, 2, 10); qqbar_add(x, x, y); qqbar_sub(x, x, y); n = 1 + n_randint(state, 4); qqbar_root_ui(y, x, n); if (n_randint(state, 2)) { qqbar_pow_ui(z, y, n); } else { if (n == 1) { qqbar_set(z, y); } else if (n == 2) { qqbar_binary_op(z, y, y, 2); } else if (n == 3) { qqbar_binary_op(z, y, y, 2); qqbar_binary_op(z, z, y, 2); } else { qqbar_binary_op(z, y, y, 2); qqbar_binary_op(z, z, z, 2); } } if (!qqbar_equal(x, z) || (n > 1 && qqbar_csgn(y) == -1)) { flint_printf("FAIL!\n"); flint_printf("n = %wu\n\n", n); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-roots_fmpz_poly.c000066400000000000000000000042541407704557200211100ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "arb_fmpz_poly.h" #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("roots_fmpz_poly...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { fmpz_poly_t poly, f; qqbar_ptr r; acb_t x, y; slong i, d, prec; fmpz_poly_init(poly); fmpz_poly_init(f); fmpz_poly_randtest(poly, state, 10, 100); if (n_randint(state, 2)) { fmpz_poly_randtest_not_zero(f, state, 5, 10); fmpz_poly_pow(f, f, 1 + n_randint(state, 3)); fmpz_poly_mul(poly, poly, f); } d = fmpz_poly_degree(poly); d = FLINT_MAX(d, 0); acb_init(x); acb_init(y); r = _qqbar_vec_init(d); qqbar_roots_fmpz_poly(r, poly, 0); for (i = 0; i < d; i++) { prec = 2 * QQBAR_DEFAULT_PREC; qqbar_get_acb(x, r + i, prec); arb_fmpz_poly_evaluate_acb(y, poly, x, prec); if (!acb_contains_zero(y)) { flint_printf("FAIL!\n"); flint_printf("i = %wd\n\n", i); flint_printf("poly = "); fmpz_poly_print(poly); flint_printf("\n\n"); flint_printf("r = "); qqbar_print(r + i); flint_printf("\n\n"); flint_printf("x = "); acb_printn(x, 100, 0); flint_printf("\n\n"); flint_printf("y = "); acb_printn(y, 100, 0); flint_printf("\n\n"); flint_abort(); } } fmpz_poly_clear(poly); fmpz_poly_clear(f); _qqbar_vec_clear(r, d); acb_clear(x); acb_clear(y); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-sec_pi.c000066400000000000000000000034271407704557200171060ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("sec_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 200 * calcium_test_multiplier(); iter++) { qqbar_t x; arb_t z, w; fmpq_t t; slong p; ulong q; slong prec; qqbar_init(x); arb_init(z); arb_init(w); fmpq_init(t); q = 1 + n_randint(state, 20); p = n_randint(state, 1000); p -= 500; prec = 2 + n_randint(state, 1000); fmpq_set_si(t, p, q); arb_cos_pi_fmpq(w, t, prec); arb_inv(w, w, prec); if (arb_is_finite(w)) { qqbar_sec_pi(x, p, q); qqbar_get_arb(z, x, prec); if (!arb_overlaps(z, w)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("z = "); arb_printn(z, 200, 0); flint_printf("\n\n"); flint_printf("w = "); arb_printn(w, 200, 0); flint_printf("\n\n"); flint_printf("p, q = %wd %wu\n\n", p, q); flint_abort(); } } qqbar_clear(x); arb_clear(z); arb_clear(w); fmpq_clear(t); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-set_d.c000066400000000000000000000035151407704557200167400ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("set_d..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { double x; qqbar_t z; arb_t a, b; int ok; qqbar_init(z); arb_init(a); arb_init(b); x = d_randtest_special(state, -1100, 1100); ok = qqbar_set_d(z, x); qqbar_get_arb(a, z, 53); arb_set_d(b, x); if (ok) { if (!arb_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); arb_print(a); flint_printf("\n\n"); flint_printf("b = "); arb_print(b); flint_printf("\n\n"); flint_abort(); } } else { if (arb_is_finite(b)) { flint_printf("FAIL!\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); arb_print(a); flint_printf("\n\n"); flint_printf("b = "); arb_print(b); flint_printf("\n\n"); flint_abort(); } } arb_clear(a); arb_clear(b); qqbar_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-set_re_im_d.c000066400000000000000000000036301407704557200201110ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("set_re_im_d..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { double x, y; qqbar_t z; acb_t a, b; int ok; qqbar_init(z); acb_init(a); acb_init(b); x = d_randtest_special(state, -1100, 1100); y = d_randtest_special(state, -1100, 1100); ok = qqbar_set_re_im_d(z, x, y); qqbar_get_acb(a, z, 53); acb_set_d_d(b, x, y); if (ok) { if (!acb_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); acb_print(a); flint_printf("\n\n"); flint_printf("b = "); acb_print(b); flint_printf("\n\n"); flint_abort(); } } else { if (acb_is_finite(b)) { flint_printf("FAIL!\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); acb_print(a); flint_printf("\n\n"); flint_printf("b = "); acb_print(b); flint_printf("\n\n"); flint_abort(); } } acb_clear(a); acb_clear(b); qqbar_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-sgn.c000066400000000000000000000025021407704557200164240ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("sgn...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_randtest(x, state, 4, 8); qqbar_sgn(y, x); qqbar_abs(z, x); qqbar_mul(z, z, y); if (!qqbar_equal(x, z)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-sgn_re.c000066400000000000000000000055761407704557200171300ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("sgn_re...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z; int s1, s2, s3, s4; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_randtest(x, state, 4, 10); qqbar_i(y); qqbar_mul(y, y, x); s1 = qqbar_sgn_re(x); s2 = qqbar_sgn_im(y); if (s1 != s2) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("s1 = %d", s1); flint_printf("\n\n"); flint_printf("s2 = %d", s2); flint_printf("\n\n"); flint_abort(); } qqbar_randtest(x, state, 4, 10); qqbar_randtest(y, state, 4, 10); if (n_randint(state, 2)) qqbar_add(x, x, y); else qqbar_mul(x, x, y); qqbar_i(y); qqbar_mul(y, y, x); s1 = qqbar_sgn_re(x); s2 = qqbar_sgn_im(y); if (s1 != s2) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("s1 = %d", s1); flint_printf("\n\n"); flint_printf("s2 = %d", s2); flint_printf("\n\n"); flint_abort(); } qqbar_randtest_real(x, state, 2, 100); qqbar_randtest_real(y, state, 2, 100); s1 = qqbar_sgn_re(x); s2 = qqbar_sgn_re(y); qqbar_i(z); qqbar_mul(y, y, z); qqbar_add(x, x, y); s3 = qqbar_sgn_re(x); s4 = qqbar_sgn_im(x); if (s1 != s3 || s2 != s4) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("s1 = %d", s1); flint_printf("\n\n"); flint_printf("s2 = %d", s2); flint_printf("\n\n"); flint_printf("s3 = %d", s3); flint_printf("\n\n"); flint_printf("s4 = %d", s4); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-sin_pi.c000066400000000000000000000032351407704557200171220ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("sin_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x; arb_t z, w; fmpq_t t; slong p; ulong q; slong prec; qqbar_init(x); arb_init(z); arb_init(w); fmpq_init(t); q = 1 + n_randint(state, 30); p = n_randint(state, 1000); p -= 500; prec = 2 + n_randint(state, 1000); qqbar_sin_pi(x, p, q); qqbar_get_arb(z, x, prec); fmpq_set_si(t, p, q); arb_sin_pi_fmpq(w, t, prec); if (!arb_overlaps(z, w)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("z = "); arb_printn(z, 200, 0); flint_printf("\n\n"); flint_printf("w = "); arb_printn(w, 200, 0); flint_printf("\n\n"); flint_printf("p, q = %wd %wu\n\n", p, q); flint_abort(); } qqbar_clear(x); arb_clear(z); arb_clear(w); fmpq_clear(t); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-sub.c000066400000000000000000000122761407704557200164370ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("sub...."); fflush(stdout); flint_randinit(state); /* Check subtraction with degree-1 terms, large coefficients */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 20, 100); qqbar_randtest(y, state, 1, 100); qqbar_randtest(z, state, 1, 100); /* check (x - y) - z = x - (z + y) */ qqbar_sub(a, x, y); qqbar_sub(a, a, z); qqbar_add(b, z, y); qqbar_sub(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* Check subtraction with degree-1 terms, small coefficients */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 30, 10); qqbar_randtest(y, state, 1, 10); qqbar_randtest(z, state, 1, 10); /* check (x - y) - z = x - (z + y) */ qqbar_sub(a, x, y); qqbar_sub(a, a, z); qqbar_add(b, z, y); qqbar_sub(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* Check subtraction with higher-degree terms */ for (iter = 0; iter < 100 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 6, 10); qqbar_randtest(y, state, 6, 10); qqbar_randtest(z, state, 2, 10); /* check (x - y) - z = x - (z + y) */ qqbar_sub(a, x, y); qqbar_sub(a, a, z); qqbar_add(b, z, y); qqbar_sub(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } /* More iterations, low degree */ for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { qqbar_t x, y, z, a, b; qqbar_init(x); qqbar_init(y); qqbar_init(z); qqbar_init(a); qqbar_init(b); qqbar_randtest(x, state, 4, 10); qqbar_randtest(y, state, 3, 10); qqbar_randtest(z, state, 2, 10); /* check (x - y) - z = x - (z + y) */ qqbar_sub(a, x, y); qqbar_sub(a, a, z); qqbar_add(b, z, y); qqbar_sub(b, x, b); if (!qqbar_equal(a, b)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("y = "); qqbar_print(y); flint_printf("\n\n"); flint_printf("z = "); qqbar_print(z); flint_printf("\n\n"); flint_printf("a = "); qqbar_print(a); flint_printf("\n\n"); flint_printf("b = "); qqbar_print(b); flint_printf("\n\n"); flint_abort(); } qqbar_clear(x); qqbar_clear(y); qqbar_clear(z); qqbar_clear(a); qqbar_clear(b); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/test/t-tan_pi.c000066400000000000000000000034771407704557200171230ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" int main() { slong iter; flint_rand_t state; flint_printf("tan_pi...."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 500 * calcium_test_multiplier(); iter++) { qqbar_t x; arb_t z, w; fmpq_t t; slong p; ulong q; slong prec; qqbar_init(x); arb_init(z); arb_init(w); fmpq_init(t); q = 1 + n_randint(state, 30); p = n_randint(state, 1000); p -= 500; prec = 2 + n_randint(state, 1000); fmpq_set_si(t, p, q); arb_sin_pi_fmpq(w, t, prec); arb_cos_pi_fmpq(z, t, prec); arb_div(w, w, z, prec); if (arb_is_finite(w)) { qqbar_tan_pi(x, p, q); qqbar_get_arb(z, x, prec); if (!arb_overlaps(z, w)) { flint_printf("FAIL!\n"); flint_printf("x = "); qqbar_print(x); flint_printf("\n\n"); flint_printf("z = "); arb_printn(z, 200, 0); flint_printf("\n\n"); flint_printf("w = "); arb_printn(w, 200, 0); flint_printf("\n\n"); flint_printf("p, q = %wd %wu\n\n", p, q); flint_abort(); } } qqbar_clear(x); arb_clear(z); arb_clear(w); fmpq_clear(t); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/qqbar/validate_enclosure.c000066400000000000000000000125051407704557200202710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "arb_fmpz_poly.h" #include "qqbar.h" int _qqbar_validate_uniqueness(acb_t res, const fmpz_poly_t poly, const acb_t z, slong prec) { if (!acb_is_finite(z) || fmpz_poly_degree(poly) < 1) { if (res != NULL) acb_set(res, z); return 0; } else if (acb_is_exact(z) || fmpz_poly_degree(poly) == 1) { if (res != NULL) acb_set(res, z); return 1; } else { slong acc; acb_t z2, zmid, t, u; fmpz_poly_t deriv; mag_t zmag, eps; int pure_real, pure_imag, ans; /* int attempt; */ pure_real = acb_is_real(z); pure_imag = arb_is_zero(acb_realref(z)); if (prec == 0) { acc = acb_rel_accuracy_bits(z); /* todo: maybe use the bits * degree of poly instead as bound */ acc = FLINT_MIN(acc, ARF_PREC_EXACT / 4); prec = FLINT_MAX(acc, 32) * 2 + 10; } acb_init(z2); acb_init(zmid); acb_init(t); acb_init(u); mag_init(eps); mag_init(zmag); fmpz_poly_init(deriv); ans = 0; /* for (attempt = 0; attempt < 2 && ans == 0; attempt++) */ { acb_get_mag(zmag, z); /* Slightly inflate enclosure -- needed e.g. in case of complex interval with one very narrow real/imaginary part */ if (1) { mag_mul_2exp_si(zmag, zmag, -3 * prec / 4); mag_hypot(eps, arb_radref(acb_realref(z)), arb_radref(acb_imagref(z))); mag_mul_2exp_si(eps, eps, -4); mag_max(eps, eps, zmag); } acb_set(z2, z); if (pure_real) arb_add_error_mag(acb_realref(z2), eps); else if (pure_imag) arb_add_error_mag(acb_imagref(z2), eps); else acb_add_error_mag(z2, eps); acb_get_mid(zmid, z2); fmpz_poly_derivative(deriv, poly); /* Do one interval Newton step, t = zmid - poly(zmid) / poly'(z2) */ arb_fmpz_poly_evaluate_acb(t, poly, zmid, prec); arb_fmpz_poly_evaluate_acb(u, deriv, z2, prec); acb_div(t, t, u, prec); acb_sub(t, zmid, t, prec); if (pure_real) { ans = arb_contains_interior(acb_realref(z2), acb_realref(t)); arb_zero(acb_imagref(t)); } else if (pure_imag) { ans = arb_contains_interior(acb_imagref(z2), acb_imagref(t)); arb_zero(acb_realref(t)); } else { ans = acb_contains_interior(z2, t); } } if (res != NULL) { if (ans) acb_set(res, t); else acb_set(res, z); } acb_clear(z2); acb_clear(zmid); acb_clear(t); acb_clear(u); mag_clear(eps); mag_clear(zmag); fmpz_poly_clear(deriv); return ans; } } int _qqbar_validate_existence_uniqueness(acb_t res, const fmpz_poly_t poly, const acb_t z, slong prec) { if (!acb_is_finite(z) || fmpz_poly_degree(poly) < 1) { if (res != NULL) acb_set(res, z); return 0; } else { slong acc; acb_t zmid, t, u; fmpz_poly_t deriv; int pure_real, pure_imag, ans, attempt; pure_real = acb_is_real(z); pure_imag = arb_is_zero(acb_realref(z)); if (prec == 0) { acc = acb_rel_accuracy_bits(z); /* todo: maybe use the bits * degree of poly instead as bound */ acc = FLINT_MIN(acc, ARF_PREC_EXACT / 4); prec = FLINT_MAX(acc, 32) * 2 + 10; } acb_init(zmid); acb_init(t); acb_init(u); fmpz_poly_init(deriv); ans = 0; for (attempt = 0; attempt < 2 && ans == 0; attempt++, prec *= 2) { acb_get_mid(zmid, z); fmpz_poly_derivative(deriv, poly); /* Do one interval Newton step, t = zmid - poly(zmid) / poly'(z) */ arb_fmpz_poly_evaluate_acb(t, poly, zmid, prec); arb_fmpz_poly_evaluate_acb(u, deriv, z, prec); acb_div(t, t, u, prec); acb_sub(t, zmid, t, prec); if (pure_real) ans = arb_contains_interior(acb_realref(z), acb_realref(t)) && arb_is_zero(acb_imagref(t)); else if (pure_imag) ans = arb_contains_interior(acb_imagref(z), acb_imagref(t)) && arb_is_zero(acb_realref(t)); else ans = acb_contains_interior(z, t); } if (res != NULL) { if (ans) acb_set(res, t); else acb_set(res, z); } acb_clear(zmid); acb_clear(t); acb_clear(u); fmpz_poly_clear(deriv); return ans; } } calcium-0.4.1/qqbar/write.c000066400000000000000000000022731407704557200155540ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "qqbar.h" /* Todo: document, unify and generalize. This is currently only used for the Python interface, but other wrappers will want good printing code too. */ void qqbar_writen(calcium_stream_t out, const qqbar_t x, slong n) { acb_t t; slong prec; n = FLINT_MAX(1, n); prec = n * 3.333 + 10; acb_init(t); qqbar_get_acb(t, x, prec); calcium_write_acb(out, t, n, ARB_STR_NO_RADIUS); acb_clear(t); } void qqbar_writend(calcium_stream_t out, const qqbar_t x, slong n) { qqbar_writen(out, x, n); calcium_write(out, " (deg "); calcium_write_si(out, qqbar_degree(x)); calcium_write(out, ")"); } char * qqbar_get_str_nd(const qqbar_t x, slong n) { calcium_stream_t out; calcium_stream_init_str(out); qqbar_writend(out, x, n); return out->s; } calcium-0.4.1/utils_flint.h000066400000000000000000000153701407704557200156570ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #ifndef UTILS_FLINT_H #define UTILS_FLINT_H #ifdef UTILS_FLINT_INLINES_C #define UTILS_FLINT_INLINE #else #define UTILS_FLINT_INLINE static __inline__ #endif #ifdef __cplusplus extern "C" { #endif #include "flint/fmpz_mpoly.h" #include "flint/fmpq.h" #include "calcium.h" /* Multivariate polynomials */ void fmpz_mpoly_set_gen_fmpz_poly(fmpz_mpoly_t res, slong var, const fmpz_poly_t pol, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_symmetric_gens(fmpz_mpoly_t res, ulong k, slong * vars, slong n, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_symmetric(fmpz_mpoly_t res, ulong k, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_primitive_part(fmpz_mpoly_t res, const fmpz_mpoly_t f, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_spoly(fmpz_mpoly_t res, const fmpz_mpoly_t f, const fmpz_mpoly_t g, const fmpz_mpoly_ctx_t ctx); /* Vectors of multivariate polynomials */ typedef struct { fmpz_mpoly_struct * p; slong length; slong alloc; } fmpz_mpoly_vec_struct; typedef fmpz_mpoly_vec_struct fmpz_mpoly_vec_t[1]; #define fmpz_mpoly_vec_entry(vec, i) ((vec)->p + (i)) UTILS_FLINT_INLINE void fmpz_mpoly_vec_init(fmpz_mpoly_vec_t vec, slong len, const fmpz_mpoly_ctx_t ctx) { if (len == 0) { vec->p = NULL; vec->length = 0; vec->alloc = 0; } else { slong i; vec->p = flint_malloc(sizeof(fmpz_mpoly_struct) * len); for (i = 0; i < len; i++) fmpz_mpoly_init(vec->p + i, ctx); vec->length = vec->alloc = len; } } UTILS_FLINT_INLINE void fmpz_mpoly_vec_print(const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx) { slong i; flint_printf("["); for (i = 0; i < F->length; i++) { fmpz_mpoly_print_pretty(F->p + i, NULL, ctx); if (i < F->length - 1) flint_printf(", "); } flint_printf("]"); } UTILS_FLINT_INLINE void fmpz_mpoly_vec_swap(fmpz_mpoly_vec_t x, fmpz_mpoly_vec_t y, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_vec_t tmp; *tmp = *x; *x = *y; *y = *tmp; } UTILS_FLINT_INLINE void fmpz_mpoly_vec_fit_length(fmpz_mpoly_vec_t vec, slong len, const fmpz_mpoly_ctx_t ctx) { if (len > vec->alloc) { slong i; if (len < 2 * vec->alloc) len = 2 * vec->alloc; vec->p = flint_realloc(vec->p, len * sizeof(fmpz_mpoly_struct)); for (i = vec->alloc; i < len; i++) fmpz_mpoly_init(vec->p + i, ctx); vec->alloc = len; } } UTILS_FLINT_INLINE void fmpz_mpoly_vec_clear(fmpz_mpoly_vec_t vec, const fmpz_mpoly_ctx_t ctx) { slong i; for (i = 0; i < vec->alloc; i++) fmpz_mpoly_clear(vec->p + i, ctx); flint_free(vec->p); } UTILS_FLINT_INLINE void fmpz_mpoly_vec_set(fmpz_mpoly_vec_t dest, const fmpz_mpoly_vec_t src, const fmpz_mpoly_ctx_t ctx) { if (dest != src) { slong i; fmpz_mpoly_vec_fit_length(dest, src->length, ctx); for (i = 0; i < src->length; i++) fmpz_mpoly_set(dest->p + i, src->p + i, ctx); dest->length = src->length; } } UTILS_FLINT_INLINE void fmpz_mpoly_vec_append(fmpz_mpoly_vec_t vec, const fmpz_mpoly_t f, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_vec_fit_length(vec, vec->length + 1, ctx); fmpz_mpoly_set(vec->p + vec->length, f, ctx); vec->length++; } UTILS_FLINT_INLINE slong fmpz_mpoly_vec_insert_unique(fmpz_mpoly_vec_t vec, const fmpz_mpoly_t f, const fmpz_mpoly_ctx_t ctx) { slong i; for (i = 0; i < vec->length; i++) { if (fmpz_mpoly_equal(vec->p + i, f, ctx)) return i; } fmpz_mpoly_vec_append(vec, f, ctx); return vec->length - 1; } void fmpz_mpoly_vec_set_length(fmpz_mpoly_vec_t vec, slong len, const fmpz_mpoly_ctx_t ctx); UTILS_FLINT_INLINE void fmpz_mpoly_vec_randtest_not_zero(fmpz_mpoly_vec_t vec, flint_rand_t state, slong len, slong poly_len, slong bits, ulong exp_bound, fmpz_mpoly_ctx_t ctx) { slong i; fmpz_mpoly_vec_set_length(vec, len, ctx); for (i = 0; i < len; i++) { do { fmpz_mpoly_randtest_bound(vec->p + i, state, poly_len, bits, exp_bound, ctx); } while (fmpz_mpoly_is_zero(vec->p + i, ctx)); } vec->length = len; } void fmpz_mpoly_vec_set_primitive_unique(fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx); /* Index pairs (for Buchberger algorithm) */ typedef struct { slong a; slong b; } pair_t; typedef struct { pair_t * pairs; slong length; slong alloc; } pairs_struct; typedef pairs_struct pairs_t[1]; UTILS_FLINT_INLINE void pairs_init(pairs_t vec) { vec->pairs = NULL; vec->length = 0; vec->alloc = 0; } UTILS_FLINT_INLINE void pairs_fit_length(pairs_t vec, slong len) { if (len > vec->alloc) { if (len < 2 * vec->alloc) len = 2 * vec->alloc; vec->pairs = flint_realloc(vec->pairs, len * sizeof(pair_t)); vec->alloc = len; } } UTILS_FLINT_INLINE void pairs_clear(pairs_t vec) { flint_free(vec->pairs); } UTILS_FLINT_INLINE void pairs_append(pairs_t vec, slong i, slong j) { pairs_fit_length(vec, vec->length + 1); vec->pairs[vec->length].a = i; vec->pairs[vec->length].b = j; vec->length++; } UTILS_FLINT_INLINE void pairs_insert_unique(pairs_t vec, slong i, slong j) { slong k; for (k = 0; k < vec->length; k++) { if (vec->pairs[k].a == i && vec->pairs[k].b == j) return; } pairs_append(vec, i, j); } /* Ideals and Groebner bases */ void fmpz_mpoly_reduction_primitive_part(fmpz_mpoly_t res, const fmpz_mpoly_t f, const fmpz_mpoly_vec_t I, const fmpz_mpoly_ctx_t ctx); int fmpz_mpoly_vec_is_groebner(const fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx); pair_t fmpz_mpoly_select_pop_pair(pairs_t pairs, const fmpz_mpoly_vec_t G, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_buchberger_naive(fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx); int fmpz_mpoly_buchberger_naive_with_limits(fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t F, slong ideal_len_limit, slong poly_len_limit, slong poly_bits_limit, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_vec_autoreduction(fmpz_mpoly_vec_t H, const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx); void fmpz_mpoly_vec_autoreduction_groebner(fmpz_mpoly_vec_t H, const fmpz_mpoly_vec_t G, const fmpz_mpoly_ctx_t ctx); int fmpz_mpoly_vec_is_autoreduced(const fmpz_mpoly_vec_t G, const fmpz_mpoly_ctx_t ctx); #ifdef __cplusplus } #endif #endif calcium-0.4.1/utils_flint/000077500000000000000000000000001407704557200155005ustar00rootroot00000000000000calcium-0.4.1/utils_flint/fmpz_mpoly_buchberger_naive.c000066400000000000000000000063761407704557200234260ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" static int within_limits(const fmpz_mpoly_t poly, slong poly_len_limit, slong poly_bits_limit, const fmpz_mpoly_ctx_t ctx) { slong bits; if (fmpz_mpoly_length(poly, ctx) > poly_len_limit) return 0; bits = fmpz_mpoly_max_bits(poly); bits = FLINT_ABS(bits); if (bits > poly_bits_limit) return 0; return 1; } static int fmpz_mpoly_disjoint_lt(const fmpz_mpoly_t f, const fmpz_mpoly_t g, const fmpz_mpoly_ctx_t ctx) { int result; slong i, nvars; ulong * exp1, * exp2; nvars = ctx->minfo->nvars; exp1 = flint_malloc(2 * nvars * sizeof(ulong)); exp2 = exp1 + nvars; fmpz_mpoly_get_term_exp_ui(exp1, f, 0, ctx); fmpz_mpoly_get_term_exp_ui(exp2, g, 0, ctx); result = 1; for (i = 0; i < nvars && result; i++) if (exp1[i] && exp2[i]) result = 0; flint_free(exp1); return result; } int fmpz_mpoly_buchberger_naive_with_limits(fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t F, slong ideal_len_limit, slong poly_len_limit, slong poly_bits_limit, const fmpz_mpoly_ctx_t ctx) { pairs_t B; fmpz_mpoly_t h; slong i, j, index_h; pair_t pair; int success; fmpz_mpoly_vec_set_primitive_unique(G, F, ctx); if (G->length <= 1) return 1; if (G->length >= ideal_len_limit) return 0; for (i = 0; i < G->length; i++) if (!within_limits(fmpz_mpoly_vec_entry(G, i), poly_len_limit, poly_bits_limit, ctx)) return 0; pairs_init(B); fmpz_mpoly_init(h, ctx); for (i = 0; i < G->length; i++) for (j = i + 1; j < G->length; j++) if (!fmpz_mpoly_disjoint_lt(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, j), ctx)) pairs_append(B, i, j); success = 1; while (B->length != 0) { pair = fmpz_mpoly_select_pop_pair(B, G, ctx); fmpz_mpoly_spoly(h, fmpz_mpoly_vec_entry(G, pair.a), fmpz_mpoly_vec_entry(G, pair.b), ctx); fmpz_mpoly_reduction_primitive_part(h, h, G, ctx); if (!fmpz_mpoly_is_zero(h, ctx)) { /* printf("h stats %ld, %ld, %ld\n", h->length, h->bits, G->length); */ if (G->length >= ideal_len_limit || !within_limits(h, poly_len_limit, poly_bits_limit, ctx)) { success = 0; break; } index_h = G->length; fmpz_mpoly_vec_append(G, h, ctx); for (i = 0; i < index_h; i++) if (!fmpz_mpoly_disjoint_lt(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, index_h), ctx)) pairs_append(B, i, index_h); } } fmpz_mpoly_clear(h, ctx); pairs_clear(B); return success; } void fmpz_mpoly_buchberger_naive(fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx) { fmpz_mpoly_buchberger_naive_with_limits(G, F, WORD_MAX, WORD_MAX, WORD_MAX, ctx); } calcium-0.4.1/utils_flint/fmpz_mpoly_primitive_part.c000066400000000000000000000017031407704557200231570ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" void fmpz_mpoly_primitive_part(fmpz_mpoly_t res, const fmpz_mpoly_t f, const fmpz_mpoly_ctx_t ctx) { if (res != f) fmpz_mpoly_set(res, f, ctx); if (fmpz_mpoly_is_zero(res, ctx)) return; if (fmpz_sgn(res->coeffs) < 0) fmpz_mpoly_neg(res, res, ctx); if (!fmpz_is_one(res->coeffs)) { fmpz_t c; fmpz_init(c); _fmpz_vec_content(c, res->coeffs, res->length); if (!fmpz_is_one(c)) fmpz_mpoly_scalar_divexact_fmpz(res, res, c, ctx); fmpz_clear(c); } } calcium-0.4.1/utils_flint/fmpz_mpoly_reduction_primitive_part.c000066400000000000000000000023301407704557200252300ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" void fmpz_mpoly_reduction_primitive_part(fmpz_mpoly_t res, const fmpz_mpoly_t f, const fmpz_mpoly_vec_t I, const fmpz_mpoly_ctx_t ctx) { fmpz_t scale; fmpz_mpoly_struct ** Q, ** B; slong i, len; len = I->length; fmpz_init(scale); Q = flint_malloc(sizeof(fmpz_mpoly_struct *) * len); B = flint_malloc(sizeof(fmpz_mpoly_struct *) * len); for (i = 0; i < len; i++) { Q[i] = flint_malloc(sizeof(fmpz_mpoly_struct)); fmpz_mpoly_init(Q[i], ctx); B[i] = fmpz_mpoly_vec_entry(I, i); } fmpz_mpoly_quasidivrem_ideal(scale, Q, res, f, B, len, ctx); fmpz_mpoly_primitive_part(res, res, ctx); for (i = 0; i < len; i++) { fmpz_mpoly_clear(Q[i], ctx); flint_free(Q[i]); } flint_free(Q); flint_free(B); fmpz_clear(scale); } calcium-0.4.1/utils_flint/fmpz_mpoly_select_pop_pair.c000066400000000000000000000053751407704557200233020ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" pair_t fmpz_mpoly_select_pop_pair(pairs_t pairs, const fmpz_mpoly_vec_t G, const fmpz_mpoly_ctx_t ctx) { slong len, choice, nvars; pair_t result; nvars = ctx->minfo->nvars; len = pairs->length; choice = 0; if (len > 1) { slong i, j, a, b; ulong * exp; ulong * tmp; ulong * lcm; ulong * best_lcm; ulong l, total; int best; exp = flint_malloc(sizeof(ulong) * G->length * nvars); lcm = flint_malloc(sizeof(ulong) * (nvars + 1)); tmp = flint_malloc(sizeof(ulong) * (nvars + 1)); best_lcm = flint_malloc(sizeof(ulong) * (nvars + 1)); for (i = 0; i <= nvars; i++) best_lcm[i] = UWORD_MAX; for (i = 0; i < G->length; i++) fmpz_mpoly_get_term_exp_ui(exp + i * nvars, G->p + i, 0, ctx); for (i = 0; i < len; i++) { a = pairs->pairs[i].a; b = pairs->pairs[i].b; total = 0; best = 1; if (ctx->minfo->ord == ORD_LEX) { for (j = 0; j < nvars; j++) { l = FLINT_MAX(exp[a * nvars + j], exp[b * nvars + j]); if (l > best_lcm[j]) { best = 0; break; } lcm[j] = l; total += l; /* total degree */ } } else /* todo: correct order */ { for (j = 0; j < nvars; j++) { l = FLINT_MAX(exp[a * nvars + j], exp[b * nvars + j]); total += l; /* total degree */ if (total >= best_lcm[j]) { best = 0; break; } lcm[j] = l; } } if (best) { for (j = 0; j < nvars; j++) best_lcm[j] = lcm[j]; best_lcm[nvars] = total; choice = i; } } flint_free(exp); flint_free(tmp); flint_free(lcm); flint_free(best_lcm); } result = pairs->pairs[choice]; pairs->pairs[choice] = pairs->pairs[pairs->length - 1]; pairs->length--; return result; } calcium-0.4.1/utils_flint/fmpz_mpoly_spoly.c000066400000000000000000000033261407704557200212720ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" void fmpz_mpoly_spoly(fmpz_mpoly_t res, const fmpz_mpoly_t f, const fmpz_mpoly_t g, const fmpz_mpoly_ctx_t ctx) { slong n, i; ulong * exp, * expf, * expg; fmpz_t c, d; fmpz_mpoly_t T, U; if (f->length == 0 || g->length == 0) { fmpz_mpoly_zero(res, ctx); return; } n = ctx->minfo->nvars; exp = flint_malloc(sizeof(ulong) * n); expf = flint_malloc(sizeof(ulong) * n); expg = flint_malloc(sizeof(ulong) * n); fmpz_init(c); fmpz_init(d); fmpz_mpoly_init(T, ctx); fmpz_mpoly_init(U, ctx); fmpz_mpoly_get_term_exp_ui(expf, f, 0, ctx); fmpz_mpoly_get_term_exp_ui(expg, g, 0, ctx); for (i = 0; i < n; i++) exp[i] = FLINT_MAX(expf[i], expg[i]); fmpz_lcm(c, f->coeffs, g->coeffs); fmpz_divexact(d, c, g->coeffs); fmpz_divexact(c, c, f->coeffs); for (i = 0; i < n; i++) { expf[i] = exp[i] - expf[i]; expg[i] = exp[i] - expg[i]; } fmpz_mpoly_set_coeff_fmpz_ui(T, c, expf, ctx); fmpz_mpoly_mul(T, T, f, ctx); fmpz_mpoly_set_coeff_fmpz_ui(U, d, expg, ctx); fmpz_mpoly_mul(U, U, g, ctx); fmpz_mpoly_sub(res, T, U, ctx); flint_free(exp); flint_free(expf); flint_free(expg); fmpz_clear(c); fmpz_clear(d); fmpz_mpoly_clear(T, ctx); fmpz_mpoly_clear(U, ctx); } calcium-0.4.1/utils_flint/fmpz_mpoly_symmetric.c000066400000000000000000000036141407704557200221400ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" void fmpz_mpoly_symmetric_gens(fmpz_mpoly_t res, ulong k, slong * vars, slong n, const fmpz_mpoly_ctx_t ctx) { ulong * exp; slong * c; slong nvars, i, j; if (k == 0) { fmpz_mpoly_one(res, ctx); return; } fmpz_mpoly_zero(res, ctx); if (k > n) return; nvars = ctx->minfo->nvars; /* Generate all combinations (Knuth algorithm L). Todo: Knuth algorithm T is faster. */ c = flint_malloc(sizeof(slong) * (k + 2)); exp = flint_calloc(nvars, sizeof(ulong)); for (j = 0; j < k; j++) c[j] = j; c[k] = n; c[k + 1] = 0; while (1) { /* Visit this combination */ for (i = 0; i < n; i++) exp[vars[i]] = 0; for (i = 0; i < k; i++) exp[vars[c[i]]] = 1; fmpz_mpoly_push_term_ui_ui(res, 1, exp, ctx); j = 1; while (c[j - 1] + 1 == c[j]) { c[j - 1] = j - 1; j++; if (c[j - 1] + 1 != c[j]) break; } if (j > k) break; c[j - 1]++; } fmpz_mpoly_sort_terms(res, ctx); flint_free(c); flint_free(exp); } void fmpz_mpoly_symmetric(fmpz_mpoly_t res, ulong k, const fmpz_mpoly_ctx_t ctx) { slong i, nvars; slong * vars; nvars = ctx->minfo->nvars; vars = flint_malloc(sizeof(slong) * nvars); for (i = 0; i < nvars; i++) vars[i] = i; fmpz_mpoly_symmetric_gens(res, k, vars, nvars, ctx); flint_free(vars); } calcium-0.4.1/utils_flint/fmpz_mpoly_vec_autoreduction.c000066400000000000000000000065761407704557200236600ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" void fmpz_mpoly_vec_autoreduction(fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t Gin, const fmpz_mpoly_ctx_t ctx) { slong i, j; if (G != Gin) fmpz_mpoly_vec_set(G, Gin, ctx); /* Content removal */ for (i = 0; i < G->length; i++) fmpz_mpoly_primitive_part(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, i), ctx); /* Make sure there are no duplicate or zero entries */ for (i = 0; i < G->length; i++) { if (fmpz_mpoly_is_zero(fmpz_mpoly_vec_entry(G, i), ctx)) { fmpz_mpoly_swap(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, G->length - 1), ctx); fmpz_mpoly_vec_set_length(G, G->length - 1, ctx); } else { for (j = i + 1; j < G->length; j++) { if (fmpz_mpoly_equal(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, j), ctx)) { fmpz_mpoly_swap(fmpz_mpoly_vec_entry(G, j), fmpz_mpoly_vec_entry(G, G->length - 1), ctx); fmpz_mpoly_vec_set_length(G, G->length - 1, ctx); } } } } /* Now do inter-reduction */ if (G->length >= 2) { fmpz_t scale; fmpz_mpoly_struct ** Q, ** B; fmpz_mpoly_t h; slong alloc; int changed; alloc = G->length - 1; fmpz_init(scale); fmpz_mpoly_init(h, ctx); Q = flint_malloc(sizeof(fmpz_mpoly_struct *) * alloc); B = flint_malloc(sizeof(fmpz_mpoly_struct *) * alloc); for (i = 0; i < alloc; i++) { Q[i] = flint_malloc(sizeof(fmpz_mpoly_struct)); fmpz_mpoly_init(Q[i], ctx); } while (G->length >= 2) { changed = 0; for (i = 0; i < G->length; i++) { for (j = 0; j < i; j++) B[j] = fmpz_mpoly_vec_entry(G, j); for (j = i + 1; j < G->length; j++) B[j - 1] = fmpz_mpoly_vec_entry(G, j); fmpz_mpoly_quasidivrem_ideal(scale, Q, h, fmpz_mpoly_vec_entry(G, i), B, G->length - 1, ctx); fmpz_mpoly_primitive_part(h, h, ctx); if (!fmpz_mpoly_equal(h, fmpz_mpoly_vec_entry(G, i), ctx)) { changed = 1; fmpz_mpoly_swap(h, fmpz_mpoly_vec_entry(G, i), ctx); } if (fmpz_mpoly_is_zero(fmpz_mpoly_vec_entry(G, i), ctx)) { fmpz_mpoly_swap(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, G->length - 1), ctx); fmpz_mpoly_vec_set_length(G, G->length - 1, ctx); i--; } } if (!changed) break; } for (i = 0; i < alloc; i++) { fmpz_mpoly_clear(Q[i], ctx); flint_free(Q[i]); } flint_free(Q); flint_free(B); fmpz_clear(scale); fmpz_mpoly_clear(h, ctx); } } calcium-0.4.1/utils_flint/fmpz_mpoly_vec_autoreduction_groebner.c000066400000000000000000000101231407704557200255220ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" static int monomial_divides(const ulong * exp1, const ulong * exp2, slong nvars) { slong i; for (i = 0; i < nvars; i++) if (exp1[i] > exp2[i]) return 0; return 1; } void fmpz_mpoly_vec_autoreduction_groebner(fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t Gin, const fmpz_mpoly_ctx_t ctx) { slong i, j, nvars; ulong * exp1, * exp2; if (G != Gin) fmpz_mpoly_vec_set(G, Gin, ctx); /* Content removal */ for (i = 0; i < G->length; i++) fmpz_mpoly_primitive_part(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, i), ctx); /* Make sure there are no duplicate or zero entries */ for (i = 0; i < G->length; i++) { if (fmpz_mpoly_is_zero(fmpz_mpoly_vec_entry(G, i), ctx)) { fmpz_mpoly_swap(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, G->length - 1), ctx); fmpz_mpoly_vec_set_length(G, G->length - 1, ctx); } else { for (j = i + 1; j < G->length; j++) { if (fmpz_mpoly_equal(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, j), ctx)) { fmpz_mpoly_swap(fmpz_mpoly_vec_entry(G, j), fmpz_mpoly_vec_entry(G, G->length - 1), ctx); fmpz_mpoly_vec_set_length(G, G->length - 1, ctx); } } } } if (G->length <= 1) return; /* First filter based on divisibility of leading terms */ nvars = ctx->minfo->nvars; exp1 = flint_malloc(nvars * sizeof(ulong)); exp2 = flint_malloc(nvars * sizeof(ulong)); for (i = 0; i < G->length; i++) { fmpz_mpoly_get_term_exp_ui(exp1, fmpz_mpoly_vec_entry(G, i), 0, ctx); for (j = 0; j < G->length; j++) { if (i != j) { fmpz_mpoly_get_term_exp_ui(exp2, fmpz_mpoly_vec_entry(G, j), 0, ctx); if (monomial_divides(exp2, exp1, nvars)) { fmpz_mpoly_swap(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, G->length - 1), ctx); fmpz_mpoly_vec_set_length(G, G->length - 1, ctx); break; } } } } flint_free(exp1); flint_free(exp2); /* Now do inter-reduction */ if (G->length >= 2) { fmpz_t scale; fmpz_mpoly_struct ** Q, ** B; slong i, j, alloc; alloc = G->length - 1; fmpz_init(scale); Q = flint_malloc(sizeof(fmpz_mpoly_struct *) * alloc); B = flint_malloc(sizeof(fmpz_mpoly_struct *) * alloc); for (i = 0; i < alloc; i++) { Q[i] = flint_malloc(sizeof(fmpz_mpoly_struct)); fmpz_mpoly_init(Q[i], ctx); } for (i = 0; i < G->length; i++) { for (j = 0; j < i; j++) B[j] = fmpz_mpoly_vec_entry(G, j); for (j = i + 1; j < G->length; j++) B[j - 1] = fmpz_mpoly_vec_entry(G, j); fmpz_mpoly_quasidivrem_ideal(scale, Q, fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, i), B, G->length - 1, ctx); fmpz_mpoly_primitive_part(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, i), ctx); if (fmpz_mpoly_is_zero(fmpz_mpoly_vec_entry(G, i), ctx)) { fmpz_mpoly_swap(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, G->length - 1), ctx); fmpz_mpoly_vec_set_length(G, G->length - 1, ctx); i--; } } for (i = 0; i < alloc; i++) { fmpz_mpoly_clear(Q[i], ctx); flint_free(Q[i]); } flint_free(Q); flint_free(B); fmpz_clear(scale); } } calcium-0.4.1/utils_flint/fmpz_mpoly_vec_is_autoreduced.c000066400000000000000000000033211407704557200237530ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" int fmpz_mpoly_vec_is_autoreduced(const fmpz_mpoly_vec_t G, const fmpz_mpoly_ctx_t ctx) { slong i, j, len, alloc; fmpz_mpoly_t h; fmpz_t scale; fmpz_mpoly_struct ** Q, ** B; int result; len = G->length; alloc = len - 1; if (len == 0) return 1; fmpz_init(scale); Q = flint_malloc(sizeof(fmpz_mpoly_struct *) * alloc); B = flint_malloc(sizeof(fmpz_mpoly_struct *) * alloc); for (i = 0; i < alloc; i++) { Q[i] = flint_malloc(sizeof(fmpz_mpoly_struct)); fmpz_mpoly_init(Q[i], ctx); } fmpz_mpoly_init(h, ctx); result = 1; for (i = 0; i < len && result; i++) { for (j = 0; j < i; j++) B[j] = fmpz_mpoly_vec_entry(G, j); for (j = i + 1; j < G->length; j++) B[j - 1] = fmpz_mpoly_vec_entry(G, j); fmpz_mpoly_quasidivrem_ideal(scale, Q, h, fmpz_mpoly_vec_entry(G, i), B, G->length - 1, ctx); fmpz_mpoly_primitive_part(h, h, ctx); if (fmpz_mpoly_is_zero(h, ctx) || !fmpz_mpoly_equal(h, fmpz_mpoly_vec_entry(G, i), ctx)) result = 0; } for (i = 0; i < alloc; i++) { fmpz_mpoly_clear(Q[i], ctx); flint_free(Q[i]); } fmpz_mpoly_clear(h, ctx); flint_free(Q); flint_free(B); fmpz_clear(scale); return result; } calcium-0.4.1/utils_flint/fmpz_mpoly_vec_is_groebner.c000066400000000000000000000025141407704557200232550ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" int fmpz_mpoly_vec_is_groebner(const fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx) { slong i, j, len; fmpz_mpoly_t h; int result; len = G->length; if (len == 0) return 1; fmpz_mpoly_init(h, ctx); result = 1; for (i = 0; i < len && result; i++) { for (j = i + 1; j < len && result; j++) { fmpz_mpoly_spoly(h, fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, j), ctx); fmpz_mpoly_reduction_primitive_part(h, h, G, ctx); if (!fmpz_mpoly_is_zero(h, ctx)) result = 0; } } if (F != NULL) { for (i = 0; i < F->length && result; i++) { fmpz_mpoly_reduction_primitive_part(h, fmpz_mpoly_vec_entry(F, i), G, ctx); if (!fmpz_mpoly_is_zero(h, ctx)) result = 0; } } fmpz_mpoly_clear(h, ctx); return result; } calcium-0.4.1/utils_flint/fmpz_mpoly_vec_set_length.c000066400000000000000000000015351407704557200231150ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" void fmpz_mpoly_vec_set_length(fmpz_mpoly_vec_t vec, slong len, const fmpz_mpoly_ctx_t ctx) { slong i; if (len > vec->length) { fmpz_mpoly_vec_fit_length(vec, len, ctx); for (i = vec->length; i < len; i++) fmpz_mpoly_zero(vec->p + i, ctx); } else if (len < vec->length) { for (i = len; i < vec->length; i++) fmpz_mpoly_zero(vec->p + i, ctx); } vec->length = len; } calcium-0.4.1/utils_flint/fmpz_mpoly_vec_set_primitive_unique.c000066400000000000000000000030241407704557200252250ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" void fmpz_mpoly_vec_set_primitive_unique(fmpz_mpoly_vec_t G, const fmpz_mpoly_vec_t F, const fmpz_mpoly_ctx_t ctx) { slong i, j, len; fmpz_mpoly_vec_set(G, F, ctx); len = G->length; for (i = 0; i < len; i++) { /* skip zero */ if (fmpz_mpoly_is_zero(fmpz_mpoly_vec_entry(G, i), ctx)) { fmpz_mpoly_swap(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, len - 1), ctx); G->length--; len--; i--; } else { fmpz_mpoly_primitive_part(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, i), ctx); for (j = 0; j < i; j++) { if (fmpz_mpoly_equal(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, j), ctx)) { fmpz_mpoly_zero(fmpz_mpoly_vec_entry(G, i), ctx); fmpz_mpoly_swap(fmpz_mpoly_vec_entry(G, i), fmpz_mpoly_vec_entry(G, len - 1), ctx); G->length--; len--; i--; break; } } } } } calcium-0.4.1/utils_flint/inlines.c000066400000000000000000000006741407704557200173140ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #define UTILS_FLINT_INLINES_C #include "utils_flint.h" calcium-0.4.1/utils_flint/set_gen_fmpz_poly.c000066400000000000000000000034321407704557200213710ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "utils_flint.h" void fmpz_mpoly_set_gen_fmpz_poly(fmpz_mpoly_t res, slong var, const fmpz_poly_t pol, const fmpz_mpoly_ctx_t ctx) { if (fmpz_poly_is_zero(pol)) { fmpz_mpoly_zero(res, ctx); } else if (pol->length == 1) { fmpz_mpoly_set_fmpz(res, pol->coeffs, ctx); } else if (pol->length == 2) { fmpz_mpoly_gen(res, var, ctx); fmpz_mpoly_scalar_mul_fmpz(res, res, pol->coeffs + 1, ctx); fmpz_mpoly_add_fmpz(res, res, pol->coeffs + 0, ctx); } else { slong len, num, i; ulong * exp; len = pol->length; exp = flint_malloc(fmpz_mpoly_ctx_nvars(ctx) * sizeof(ulong)); /* TMP_ALLOC? */ for (i = 0; i < fmpz_mpoly_ctx_nvars(ctx); i++) exp[i] = 0; num = 1; for (i = pol->length - 2; i >= 0; i--) num += !fmpz_is_zero(pol->coeffs + i); fmpz_mpoly_fit_bits(res, FLINT_BIT_COUNT(len), ctx); fmpz_mpoly_fit_length(res, num, ctx); /* xxx? zero fmpzs? */ res->length = 0; /* xxx: reverse ordering */ for (i = len - 1; i >= 0; i--) { if (!fmpz_is_zero(pol->coeffs + i)) { exp[var] = i; fmpz_mpoly_push_term_fmpz_ui(res, pol->coeffs + i, exp, ctx); } } _fmpz_mpoly_set_length(res, num, ctx); flint_free(exp); } } calcium-0.4.1/utils_flint/test/000077500000000000000000000000001407704557200164575ustar00rootroot00000000000000calcium-0.4.1/utils_flint/test/t-fmpz_mpoly_buchberger_naive.c000066400000000000000000000060621407704557200246360ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" #include "utils_flint.h" int main() { slong iter; flint_rand_t state; flint_printf("fmpz_mpoly_buchberger_naive..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_vec_t F, G, H; slong nvars; fmpz_mpoly_ctx_init_rand(ctx, state, 4); nvars = ctx->minfo->nvars; fmpz_mpoly_vec_init(F, 0, ctx); fmpz_mpoly_vec_init(G, 0, ctx); fmpz_mpoly_vec_init(H, 0, ctx); /* flint_printf("iter %ld %ld %d\n\n", iter, nvars, ctx->minfo->ord); printf("--------------------------------------------------------------------\n"); */ if (nvars == 4) fmpz_mpoly_vec_randtest_not_zero(F, state, 1 + n_randint(state, 3), 1 + n_randint(state, 3), 1 + n_randint(state, 3), 1 + n_randint(state, 2), ctx); else if (nvars == 3) fmpz_mpoly_vec_randtest_not_zero(F, state, 1 + n_randint(state, 4), 1 + n_randint(state, 4), 1 + n_randint(state, 4), 1 + n_randint(state, 2), ctx); else fmpz_mpoly_vec_randtest_not_zero(F, state, 1 + n_randint(state, 5), 1 + n_randint(state, 5), 1 + n_randint(state, 5), 1 + n_randint(state, 3), ctx); /* flint_printf("F = "); fmpz_mpoly_vec_print(F, ctx); flint_printf("\n"); */ fmpz_mpoly_buchberger_naive(G, F, ctx); /* flint_printf("G = "); fmpz_mpoly_vec_print(G, ctx); flint_printf("\n"); */ if (!fmpz_mpoly_vec_is_groebner(G, F, ctx)) { flint_printf("FAIL\n\n"); mpoly_ordering_print(ctx->minfo->ord); printf("\n"); flint_printf("F = "); fmpz_mpoly_vec_print(F, ctx); flint_printf("\n"); flint_printf("G = "); fmpz_mpoly_vec_print(G, ctx); flint_printf("\n"); flint_abort(); } fmpz_mpoly_vec_autoreduction_groebner(H, G, ctx); if (!fmpz_mpoly_vec_is_groebner(H, F, ctx) || !fmpz_mpoly_vec_is_autoreduced(H, ctx)) { flint_printf("FAIL (reduced GB)\n\n"); mpoly_ordering_print(ctx->minfo->ord); printf("\n"); flint_printf("F = "); fmpz_mpoly_vec_print(F, ctx); flint_printf("\n"); flint_printf("G = "); fmpz_mpoly_vec_print(G, ctx); flint_printf("\n"); flint_printf("H = "); fmpz_mpoly_vec_print(H, ctx); flint_printf("\n"); flint_abort(); } fmpz_mpoly_vec_clear(F, ctx); fmpz_mpoly_vec_clear(G, ctx); fmpz_mpoly_vec_clear(H, ctx); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/utils_flint/test/t-fmpz_mpoly_set_gen_fmpz_poly.c000066400000000000000000000040121407704557200250600ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" #include "utils_flint.h" int main() { slong iter; flint_rand_t state; flint_printf("fmpz_mpoly_set_gen_fmpz_poly..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_t F, G, x, t; fmpz_poly_t f; slong nvars, i, j; fmpz_poly_init(f); fmpz_mpoly_ctx_init_rand(ctx, state, 4); nvars = ctx->minfo->nvars; fmpz_mpoly_init(F, ctx); fmpz_mpoly_init(G, ctx); fmpz_mpoly_init(x, ctx); fmpz_mpoly_init(t, ctx); fmpz_mpoly_randtest_bound(F, state, 10, 100, 100, ctx); fmpz_poly_randtest(f, state, 10, 100); i = n_randint(state, nvars); fmpz_mpoly_set_gen_fmpz_poly(F, i, f, ctx); fmpz_mpoly_gen(x, i, ctx); for (j = 0; j < f->length; j++) { fmpz_mpoly_pow_ui(t, x, j, ctx); fmpz_mpoly_scalar_mul_fmpz(t, t, f->coeffs + j, ctx); fmpz_mpoly_add(G, G, t, ctx); } if (!fmpz_mpoly_equal(F, G, ctx)) { flint_printf("FAIL\n"); fmpz_mpoly_print_pretty(F, NULL, ctx); flint_printf("\n\n"); fmpz_mpoly_print_pretty(G, NULL, ctx); flint_printf("\n\n"); flint_abort(); } fmpz_poly_clear(f); fmpz_mpoly_clear(F, ctx); fmpz_mpoly_clear(G, ctx); fmpz_mpoly_clear(x, ctx); fmpz_mpoly_clear(t, ctx); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/utils_flint/test/t-fmpz_mpoly_symmetric.c000066400000000000000000000025131407704557200233550ustar00rootroot00000000000000/* Copyright (C) 2021 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" #include "utils_flint.h" int main() { slong iter; flint_rand_t state; flint_printf("fmpz_mpoly_symmetric..."); fflush(stdout); flint_randinit(state); /* todo; this does noting useful right now except verifying that the function can be called */ for (iter = 0; iter < 1000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_t F; slong nvars, n, k; slong vars[10]; fmpz_mpoly_ctx_init_rand(ctx, state, 4); nvars = ctx->minfo->nvars; n = n_randint(state, nvars + 1); for (k = 0; k < n; k++) vars[k] = k; k = n_randint(state, 5); fmpz_mpoly_init(F, ctx); fmpz_mpoly_symmetric_gens(F, k, vars, n, ctx); fmpz_mpoly_clear(F, ctx); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; } calcium-0.4.1/utils_flint/test/t-fmpz_mpoly_vec_autoreduction.c000066400000000000000000000031751407704557200250700ustar00rootroot00000000000000/* Copyright (C) 2020 Fredrik Johansson This file is part of Calcium. Calcium is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See . */ #include "calcium.h" #include "utils_flint.h" int main() { slong iter; flint_rand_t state; flint_printf("fmpz_mpoly_vec_autoreduction..."); fflush(stdout); flint_randinit(state); for (iter = 0; iter < 10000 * calcium_test_multiplier(); iter++) { fmpz_mpoly_ctx_t ctx; fmpz_mpoly_vec_t F, G; fmpz_mpoly_ctx_init_rand(ctx, state, 4); fmpz_mpoly_vec_init(F, 0, ctx); fmpz_mpoly_vec_init(G, 0, ctx); fmpz_mpoly_vec_randtest_not_zero(F, state, 1 + n_randint(state, 5), 1 + n_randint(state, 4), 1 + n_randint(state, 3), 1 + n_randint(state, 2), ctx); fmpz_mpoly_vec_autoreduction(G, F, ctx); if (!fmpz_mpoly_vec_is_autoreduced(G, ctx)) { flint_printf("FAIL\n\n"); mpoly_ordering_print(ctx->minfo->ord); printf("\n"); flint_printf("F = "); fmpz_mpoly_vec_print(F, ctx); flint_printf("\n"); flint_printf("G = "); fmpz_mpoly_vec_print(G, ctx); flint_printf("\n"); flint_abort(); } fmpz_mpoly_vec_clear(F, ctx); fmpz_mpoly_vec_clear(G, ctx); fmpz_mpoly_ctx_clear(ctx); } flint_randclear(state); flint_cleanup(); flint_printf("PASS\n"); return EXIT_SUCCESS; }