singular-factory (empty) → 0.1
raw patch · 16 files changed
+4176/−0 lines, 16 filesdep +QuickCheckdep +basedep +containerssetup-changed
Dependencies added: QuickCheck, base, containers, directory, filepath, hgmp, process, random, singular-factory, tasty, tasty-hunit, tasty-quickcheck, text
Files
- LICENSE +674/−0
- Setup.hs +2/−0
- cpp_bits/interface.cpp +754/−0
- singular-factory.cabal +82/−0
- src/Math/Singular/Factory.hs +88/−0
- src/Math/Singular/Factory/Counting.hs +75/−0
- src/Math/Singular/Factory/Domains.hs +324/−0
- src/Math/Singular/Factory/Expr.hs +111/−0
- src/Math/Singular/Factory/GFTables.hs +145/−0
- src/Math/Singular/Factory/Internal/CanonicalForm.hs +511/−0
- src/Math/Singular/Factory/Internal/DList.hs +29/−0
- src/Math/Singular/Factory/Internal/Factory.hs +433/−0
- src/Math/Singular/Factory/Parser.hs +326/−0
- src/Math/Singular/Factory/Polynomial.hs +158/−0
- src/Math/Singular/Factory/Variables.hs +208/−0
- test/TestSuite.hs +256/−0
+ LICENSE view
@@ -0,0 +1,674 @@+ GNU GENERAL PUBLIC LICENSE+ Version 3, 29 June 2007++ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++ Preamble++ The GNU General Public License is a free, copyleft license for+software and other kinds of works.++ The licenses for most software and other practical works are designed+to take away your freedom to share and change the works. By contrast,+the GNU General Public License is intended to guarantee your freedom to+share and change all versions of a program--to make sure it remains free+software for all its users. We, the Free Software Foundation, use the+GNU General Public License for most of our software; it applies also to+any other work released this way by its authors. You can apply it to+your programs, too.++ When we speak of free software, we are referring to freedom, not+price. Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+them if you wish), that you receive source code or can get it if you+want it, that you can change the software or use pieces of it in new+free programs, and that you know you can do these things.++ To protect your rights, we need to prevent others from denying you+these rights or asking you to surrender the rights. Therefore, you have+certain responsibilities if you distribute copies of the software, or if+you modify it: responsibilities to respect the freedom of others.++ For example, if you distribute copies of such a program, whether+gratis or for a fee, you must pass on to the recipients the same+freedoms that you received. You must make sure that they, too, receive+or can get the source code. And you must show them these terms so they+know their rights.++ Developers that use the GNU GPL protect your rights with two steps:+(1) assert copyright on the software, and (2) offer you this License+giving you legal permission to copy, distribute and/or modify it.++ For the developers' and authors' protection, the GPL clearly explains+that there is no warranty for this free software. For both users' and+authors' sake, the GPL requires that modified versions be marked as+changed, so that their problems will not be attributed erroneously to+authors of previous versions.++ Some devices are designed to deny users access to install or run+modified versions of the software inside them, although the manufacturer+can do so. This is fundamentally incompatible with the aim of+protecting users' freedom to change the software. The systematic+pattern of such abuse occurs in the area of products for individuals to+use, which is precisely where it is most unacceptable. Therefore, we+have designed this version of the GPL to prohibit the practice for those+products. If such problems arise substantially in other domains, we+stand ready to extend this provision to those domains in future versions+of the GPL, as needed to protect the freedom of users.++ Finally, every program is threatened constantly by software patents.+States should not allow patents to restrict development and use of+software on general-purpose computers, but in those that do, we wish to+avoid the special danger that patents applied to a free program could+make it effectively proprietary. To prevent this, the GPL assures that+patents cannot be used to render the program non-free.++ The precise terms and conditions for copying, distribution and+modification follow.++ TERMS AND CONDITIONS++ 0. Definitions.++ "This License" refers to version 3 of the GNU General Public License.++ "Copyright" also means copyright-like laws that apply to other kinds of+works, such as semiconductor masks.++ "The Program" refers to any copyrightable work licensed under this+License. Each licensee is addressed as "you". "Licensees" and+"recipients" may be individuals or organizations.++ To "modify" a work means to copy from or adapt all or part of the work+in a fashion requiring copyright permission, other than the making of an+exact copy. The resulting work is called a "modified version" of the+earlier work or a work "based on" the earlier work.++ A "covered work" means either the unmodified Program or a work based+on the Program.++ To "propagate" a work means to do anything with it that, without+permission, would make you directly or secondarily liable for+infringement under applicable copyright law, except executing it on a+computer or modifying a private copy. Propagation includes copying,+distribution (with or without modification), making available to the+public, and in some countries other activities as well.++ To "convey" a work means any kind of propagation that enables other+parties to make or receive copies. Mere interaction with a user through+a computer network, with no transfer of a copy, is not conveying.++ An interactive user interface displays "Appropriate Legal Notices"+to the extent that it includes a convenient and prominently visible+feature that (1) displays an appropriate copyright notice, and (2)+tells the user that there is no warranty for the work (except to the+extent that warranties are provided), that licensees may convey the+work under this License, and how to view a copy of this License. If+the interface presents a list of user commands or options, such as a+menu, a prominent item in the list meets this criterion.++ 1. Source Code.++ The "source code" for a work means the preferred form of the work+for making modifications to it. "Object code" means any non-source+form of a work.++ A "Standard Interface" means an interface that either is an official+standard defined by a recognized standards body, or, in the case of+interfaces specified for a particular programming language, one that+is widely used among developers working in that language.++ The "System Libraries" of an executable work include anything, other+than the work as a whole, that (a) is included in the normal form of+packaging a Major Component, but which is not part of that Major+Component, and (b) serves only to enable use of the work with that+Major Component, or to implement a Standard Interface for which an+implementation is available to the public in source code form. A+"Major Component", in this context, means a major essential component+(kernel, window system, and so on) of the specific operating system+(if any) on which the executable work runs, or a compiler used to+produce the work, or an object code interpreter used to run it.++ The "Corresponding Source" for a work in object code form means all+the source code needed to generate, install, and (for an executable+work) run the object code and to modify the work, including scripts to+control those activities. However, it does not include the work's+System Libraries, or general-purpose tools or generally available free+programs which are used unmodified in performing those activities but+which are not part of the work. For example, Corresponding Source+includes interface definition files associated with source files for+the work, and the source code for shared libraries and dynamically+linked subprograms that the work is specifically designed to require,+such as by intimate data communication or control flow between those+subprograms and other parts of the work.++ The Corresponding Source need not include anything that users+can regenerate automatically from other parts of the Corresponding+Source.++ The Corresponding Source for a work in source code form is that+same work.++ 2. Basic Permissions.++ All rights granted under this License are granted for the term of+copyright on the Program, and are irrevocable provided the stated+conditions are met. This License explicitly affirms your unlimited+permission to run the unmodified Program. The output from running a+covered work is covered by this License only if the output, given its+content, constitutes a covered work. This License acknowledges your+rights of fair use or other equivalent, as provided by copyright law.++ You may make, run and propagate covered works that you do not+convey, without conditions so long as your license otherwise remains+in force. You may convey covered works to others for the sole purpose+of having them make modifications exclusively for you, or provide you+with facilities for running those works, provided that you comply with+the terms of this License in conveying all material for which you do+not control copyright. Those thus making or running the covered works+for you must do so exclusively on your behalf, under your direction+and control, on terms that prohibit them from making any copies of+your copyrighted material outside their relationship with you.++ Conveying under any other circumstances is permitted solely under+the conditions stated below. Sublicensing is not allowed; section 10+makes it unnecessary.++ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.++ No covered work shall be deemed part of an effective technological+measure under any applicable law fulfilling obligations under article+11 of the WIPO copyright treaty adopted on 20 December 1996, or+similar laws prohibiting or restricting circumvention of such+measures.++ When you convey a covered work, you waive any legal power to forbid+circumvention of technological measures to the extent such circumvention+is effected by exercising rights under this License with respect to+the covered work, and you disclaim any intention to limit operation or+modification of the work as a means of enforcing, against the work's+users, your or third parties' legal rights to forbid circumvention of+technological measures.++ 4. Conveying Verbatim Copies.++ You may convey verbatim copies of the Program's source code as you+receive it, in any medium, provided that you conspicuously and+appropriately publish on each copy an appropriate copyright notice;+keep intact all notices stating that this License and any+non-permissive terms added in accord with section 7 apply to the code;+keep intact all notices of the absence of any warranty; and give all+recipients a copy of this License along with the Program.++ You may charge any price or no price for each copy that you convey,+and you may offer support or warranty protection for a fee.++ 5. Conveying Modified Source Versions.++ You may convey a work based on the Program, or the modifications to+produce it from the Program, in the form of source code under the+terms of section 4, provided that you also meet all of these conditions:++ a) The work must carry prominent notices stating that you modified+ it, and giving a relevant date.++ b) The work must carry prominent notices stating that it is+ released under this License and any conditions added under section+ 7. This requirement modifies the requirement in section 4 to+ "keep intact all notices".++ c) You must license the entire work, as a whole, under this+ License to anyone who comes into possession of a copy. This+ License will therefore apply, along with any applicable section 7+ additional terms, to the whole of the work, and all its parts,+ regardless of how they are packaged. This License gives no+ permission to license the work in any other way, but it does not+ invalidate such permission if you have separately received it.++ d) If the work has interactive user interfaces, each must display+ Appropriate Legal Notices; however, if the Program has interactive+ interfaces that do not display Appropriate Legal Notices, your+ work need not make them do so.++ A compilation of a covered work with other separate and independent+works, which are not by their nature extensions of the covered work,+and which are not combined with it such as to form a larger program,+in or on a volume of a storage or distribution medium, is called an+"aggregate" if the compilation and its resulting copyright are not+used to limit the access or legal rights of the compilation's users+beyond what the individual works permit. Inclusion of a covered work+in an aggregate does not cause this License to apply to the other+parts of the aggregate.++ 6. Conveying Non-Source Forms.++ You may convey a covered work in object code form under the terms+of sections 4 and 5, provided that you also convey the+machine-readable Corresponding Source under the terms of this License,+in one of these ways:++ a) Convey the object code in, or embodied in, a physical product+ (including a physical distribution medium), accompanied by the+ Corresponding Source fixed on a durable physical medium+ customarily used for software interchange.++ b) Convey the object code in, or embodied in, a physical product+ (including a physical distribution medium), accompanied by a+ written offer, valid for at least three years and valid for as+ long as you offer spare parts or customer support for that product+ model, to give anyone who possesses the object code either (1) a+ copy of the Corresponding Source for all the software in the+ product that is covered by this License, on a durable physical+ medium customarily used for software interchange, for a price no+ more than your reasonable cost of physically performing this+ conveying of source, or (2) access to copy the+ Corresponding Source from a network server at no charge.++ c) Convey individual copies of the object code with a copy of the+ written offer to provide the Corresponding Source. This+ alternative is allowed only occasionally and noncommercially, and+ only if you received the object code with such an offer, in accord+ with subsection 6b.++ d) Convey the object code by offering access from a designated+ place (gratis or for a charge), and offer equivalent access to the+ Corresponding Source in the same way through the same place at no+ further charge. You need not require recipients to copy the+ Corresponding Source along with the object code. If the place to+ copy the object code is a network server, the Corresponding Source+ may be on a different server (operated by you or a third party)+ that supports equivalent copying facilities, provided you maintain+ clear directions next to the object code saying where to find the+ Corresponding Source. Regardless of what server hosts the+ Corresponding Source, you remain obligated to ensure that it is+ available for as long as needed to satisfy these requirements.++ e) Convey the object code using peer-to-peer transmission, provided+ you inform other peers where the object code and Corresponding+ Source of the work are being offered to the general public at no+ charge under subsection 6d.++ A separable portion of the object code, whose source code is excluded+from the Corresponding Source as a System Library, need not be+included in conveying the object code work.++ A "User Product" is either (1) a "consumer product", which means any+tangible personal property which is normally used for personal, family,+or household purposes, or (2) anything designed or sold for incorporation+into a dwelling. In determining whether a product is a consumer product,+doubtful cases shall be resolved in favor of coverage. For a particular+product received by a particular user, "normally used" refers to a+typical or common use of that class of product, regardless of the status+of the particular user or of the way in which the particular user+actually uses, or expects or is expected to use, the product. A product+is a consumer product regardless of whether the product has substantial+commercial, industrial or non-consumer uses, unless such uses represent+the only significant mode of use of the product.++ "Installation Information" for a User Product means any methods,+procedures, authorization keys, or other information required to install+and execute modified versions of a covered work in that User Product from+a modified version of its Corresponding Source. The information must+suffice to ensure that the continued functioning of the modified object+code is in no case prevented or interfered with solely because+modification has been made.++ If you convey an object code work under this section in, or with, or+specifically for use in, a User Product, and the conveying occurs as+part of a transaction in which the right of possession and use of the+User Product is transferred to the recipient in perpetuity or for a+fixed term (regardless of how the transaction is characterized), the+Corresponding Source conveyed under this section must be accompanied+by the Installation Information. But this requirement does not apply+if neither you nor any third party retains the ability to install+modified object code on the User Product (for example, the work has+been installed in ROM).++ The requirement to provide Installation Information does not include a+requirement to continue to provide support service, warranty, or updates+for a work that has been modified or installed by the recipient, or for+the User Product in which it has been modified or installed. Access to a+network may be denied when the modification itself materially and+adversely affects the operation of the network or violates the rules and+protocols for communication across the network.++ Corresponding Source conveyed, and Installation Information provided,+in accord with this section must be in a format that is publicly+documented (and with an implementation available to the public in+source code form), and must require no special password or key for+unpacking, reading or copying.++ 7. Additional Terms.++ "Additional permissions" are terms that supplement the terms of this+License by making exceptions from one or more of its conditions.+Additional permissions that are applicable to the entire Program shall+be treated as though they were included in this License, to the extent+that they are valid under applicable law. If additional permissions+apply only to part of the Program, that part may be used separately+under those permissions, but the entire Program remains governed by+this License without regard to the additional permissions.++ When you convey a copy of a covered work, you may at your option+remove any additional permissions from that copy, or from any part of+it. (Additional permissions may be written to require their own+removal in certain cases when you modify the work.) You may place+additional permissions on material, added by you to a covered work,+for which you have or can give appropriate copyright permission.++ Notwithstanding any other provision of this License, for material you+add to a covered work, you may (if authorized by the copyright holders of+that material) supplement the terms of this License with terms:++ a) Disclaiming warranty or limiting liability differently from the+ terms of sections 15 and 16 of this License; or++ b) Requiring preservation of specified reasonable legal notices or+ author attributions in that material or in the Appropriate Legal+ Notices displayed by works containing it; or++ c) Prohibiting misrepresentation of the origin of that material, or+ requiring that modified versions of such material be marked in+ reasonable ways as different from the original version; or++ d) Limiting the use for publicity purposes of names of licensors or+ authors of the material; or++ e) Declining to grant rights under trademark law for use of some+ trade names, trademarks, or service marks; or++ f) Requiring indemnification of licensors and authors of that+ material by anyone who conveys the material (or modified versions of+ it) with contractual assumptions of liability to the recipient, for+ any liability that these contractual assumptions directly impose on+ those licensors and authors.++ All other non-permissive additional terms are considered "further+restrictions" within the meaning of section 10. If the Program as you+received it, or any part of it, contains a notice stating that it is+governed by this License along with a term that is a further+restriction, you may remove that term. If a license document contains+a further restriction but permits relicensing or conveying under this+License, you may add to a covered work material governed by the terms+of that license document, provided that the further restriction does+not survive such relicensing or conveying.++ If you add terms to a covered work in accord with this section, you+must place, in the relevant source files, a statement of the+additional terms that apply to those files, or a notice indicating+where to find the applicable terms.++ Additional terms, permissive or non-permissive, may be stated in the+form of a separately written license, or stated as exceptions;+the above requirements apply either way.++ 8. Termination.++ You may not propagate or modify a covered work except as expressly+provided under this License. Any attempt otherwise to propagate or+modify it is void, and will automatically terminate your rights under+this License (including any patent licenses granted under the third+paragraph of section 11).++ However, if you cease all violation of this License, then your+license from a particular copyright holder is reinstated (a)+provisionally, unless and until the copyright holder explicitly and+finally terminates your license, and (b) permanently, if the copyright+holder fails to notify you of the violation by some reasonable means+prior to 60 days after the cessation.++ Moreover, your license from a particular copyright holder is+reinstated permanently if the copyright holder notifies you of the+violation by some reasonable means, this is the first time you have+received notice of violation of this License (for any work) from that+copyright holder, and you cure the violation prior to 30 days after+your receipt of the notice.++ Termination of your rights under this section does not terminate the+licenses of parties who have received copies or rights from you under+this License. If your rights have been terminated and not permanently+reinstated, you do not qualify to receive new licenses for the same+material under section 10.++ 9. Acceptance Not Required for Having Copies.++ You are not required to accept this License in order to receive or+run a copy of the Program. Ancillary propagation of a covered work+occurring solely as a consequence of using peer-to-peer transmission+to receive a copy likewise does not require acceptance. However,+nothing other than this License grants you permission to propagate or+modify any covered work. These actions infringe copyright if you do+not accept this License. Therefore, by modifying or propagating a+covered work, you indicate your acceptance of this License to do so.++ 10. Automatic Licensing of Downstream Recipients.++ Each time you convey a covered work, the recipient automatically+receives a license from the original licensors, to run, modify and+propagate that work, subject to this License. You are not responsible+for enforcing compliance by third parties with this License.++ An "entity transaction" is a transaction transferring control of an+organization, or substantially all assets of one, or subdividing an+organization, or merging organizations. If propagation of a covered+work results from an entity transaction, each party to that+transaction who receives a copy of the work also receives whatever+licenses to the work the party's predecessor in interest had or could+give under the previous paragraph, plus a right to possession of the+Corresponding Source of the work from the predecessor in interest, if+the predecessor has it or can get it with reasonable efforts.++ You may not impose any further restrictions on the exercise of the+rights granted or affirmed under this License. For example, you may+not impose a license fee, royalty, or other charge for exercise of+rights granted under this License, and you may not initiate litigation+(including a cross-claim or counterclaim in a lawsuit) alleging that+any patent claim is infringed by making, using, selling, offering for+sale, or importing the Program or any portion of it.++ 11. Patents.++ A "contributor" is a copyright holder who authorizes use under this+License of the Program or a work on which the Program is based. The+work thus licensed is called the contributor's "contributor version".++ A contributor's "essential patent claims" are all patent claims+owned or controlled by the contributor, whether already acquired or+hereafter acquired, that would be infringed by some manner, permitted+by this License, of making, using, or selling its contributor version,+but do not include claims that would be infringed only as a+consequence of further modification of the contributor version. For+purposes of this definition, "control" includes the right to grant+patent sublicenses in a manner consistent with the requirements of+this License.++ Each contributor grants you a non-exclusive, worldwide, royalty-free+patent license under the contributor's essential patent claims, to+make, use, sell, offer for sale, import and otherwise run, modify and+propagate the contents of its contributor version.++ In the following three paragraphs, a "patent license" is any express+agreement or commitment, however denominated, not to enforce a patent+(such as an express permission to practice a patent or covenant not to+sue for patent infringement). To "grant" such a patent license to a+party means to make such an agreement or commitment not to enforce a+patent against the party.++ If you convey a covered work, knowingly relying on a patent license,+and the Corresponding Source of the work is not available for anyone+to copy, free of charge and under the terms of this License, through a+publicly available network server or other readily accessible means,+then you must either (1) cause the Corresponding Source to be so+available, or (2) arrange to deprive yourself of the benefit of the+patent license for this particular work, or (3) arrange, in a manner+consistent with the requirements of this License, to extend the patent+license to downstream recipients. "Knowingly relying" means you have+actual knowledge that, but for the patent license, your conveying the+covered work in a country, or your recipient's use of the covered work+in a country, would infringe one or more identifiable patents in that+country that you have reason to believe are valid.++ If, pursuant to or in connection with a single transaction or+arrangement, you convey, or propagate by procuring conveyance of, a+covered work, and grant a patent license to some of the parties+receiving the covered work authorizing them to use, propagate, modify+or convey a specific copy of the covered work, then the patent license+you grant is automatically extended to all recipients of the covered+work and works based on it.++ A patent license is "discriminatory" if it does not include within+the scope of its coverage, prohibits the exercise of, or is+conditioned on the non-exercise of one or more of the rights that are+specifically granted under this License. You may not convey a covered+work if you are a party to an arrangement with a third party that is+in the business of distributing software, under which you make payment+to the third party based on the extent of your activity of conveying+the work, and under which the third party grants, to any of the+parties who would receive the covered work from you, a discriminatory+patent license (a) in connection with copies of the covered work+conveyed by you (or copies made from those copies), or (b) primarily+for and in connection with specific products or compilations that+contain the covered work, unless you entered into that arrangement,+or that patent license was granted, prior to 28 March 2007.++ Nothing in this License shall be construed as excluding or limiting+any implied license or other defenses to infringement that may+otherwise be available to you under applicable patent law.++ 12. No Surrender of Others' Freedom.++ If 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 convey a+covered work so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you may+not convey it at all. For example, if you agree to terms that obligate you+to collect a royalty for further conveying from those to whom you convey+the Program, the only way you could satisfy both those terms and this+License would be to refrain entirely from conveying the Program.++ 13. Use with the GNU Affero General Public License.++ Notwithstanding any other provision of this License, you have+permission to link or combine any covered work with a work licensed+under version 3 of the GNU Affero General Public License into a single+combined work, and to convey the resulting work. The terms of this+License will continue to apply to the part which is the covered work,+but the special requirements of the GNU Affero General Public License,+section 13, concerning interaction through a network will apply to the+combination as such.++ 14. Revised Versions of this License.++ The Free Software Foundation may publish revised and/or new versions of+the GNU General Public License from time to time. Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++ Each version is given a distinguishing version number. If the+Program specifies that a certain numbered version of the GNU General+Public License "or any later version" applies to it, you have the+option of following the terms and conditions either of that numbered+version or of any later version published by the Free Software+Foundation. If the Program does not specify a version number of the+GNU General Public License, you may choose any version ever published+by the Free Software Foundation.++ If the Program specifies that a proxy can decide which future+versions of the GNU General Public License can be used, that proxy's+public statement of acceptance of a version permanently authorizes you+to choose that version for the Program.++ Later license versions may give you additional or different+permissions. However, no additional obligations are imposed on any+author or copyright holder as a result of your choosing to follow a+later version.++ 15. Disclaimer of Warranty.++ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.++ 16. Limitation of Liability.++ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF+SUCH DAMAGES.++ 17. Interpretation of Sections 15 and 16.++ If the disclaimer of warranty and limitation of liability provided+above cannot be given local legal effect according to their terms,+reviewing courts shall apply local law that most closely approximates+an absolute waiver of all civil liability in connection with the+Program, unless a warranty or assumption of liability accompanies a+copy of the Program in return for a fee.++ END OF TERMS AND CONDITIONS++ How to Apply These Terms to Your New Programs++ If you develop a new program, and you want it to be of the greatest+possible use to the public, the best way to achieve this is to make it+free software which everyone can redistribute and change under these terms.++ To do so, attach the following notices to the program. It is safest+to attach them to the start of each source file to most effectively+state the exclusion of warranty; and each file should have at least+the "copyright" line and a pointer to where the full notice is found.++ <one line to give the program's name and a brief idea of what it does.>+ Copyright (C) <year> <name of author>++ This program is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ This program is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with this program. If not, see <https://www.gnu.org/licenses/>.++Also add information on how to contact you by electronic and paper mail.++ If the program does terminal interaction, make it output a short+notice like this when it starts in an interactive mode:++ <program> Copyright (C) <year> <name of author>+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+ This is free software, and you are welcome to redistribute it+ under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License. Of course, your program's commands+might be different; for a GUI interface, you would use an "about box".++ You should also get your employer (if you work as a programmer) or school,+if any, to sign a "copyright disclaimer" for the program, if necessary.+For more information on this, and how to apply and follow the GNU GPL, see+<https://www.gnu.org/licenses/>.++ The GNU General Public License does not permit incorporating your program+into proprietary programs. If your program is a subroutine library, you+may consider it more useful to permit linking proprietary applications with+the library. If this is what you want to do, use the GNU Lesser General+Public License instead of this License. But first, please read+<https://www.gnu.org/licenses/why-not-lgpl.html>.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cpp_bits/interface.cpp view
@@ -0,0 +1,754 @@++#include <factory/factory.h>++// -----------------------------------------------------------------------------+// types++typedef void Var; // Variable+typedef void CF; // CanonicalForm+typedef void Fac; // CFFactor = Factor<CF>+typedef void FacList; // CFFList = List<CFFactor>+typedef void Iter; // ListIterator<CFFactor>++// -----------------------------------------------------------------------------+// constants++extern "C" int level_base() { return LEVELBASE; }+extern "C" int level_trans() { return LEVELTRANS; }+extern "C" int level_quot() { return LEVELQUOT; }+extern "C" int level_expr() { return LEVELEXPR; }++// -----------------------------------------------------------------------------+// version info++extern "C"+void get_factory_version(char *str, int n)+{+ strncpy(str,FACTORYVERSION,n);+ str[n-1]=0;+}++extern "C"+void get_package_version(char *str, int n)+{+ strncpy(str,PACKAGE_VERSION,n);+ str[n-1]=0;+}++extern "C" int have_FLINT() { +#ifdef HAVE_FLINT+ return 1;+#else+ return 0;+#endif+}++extern "C" int have_NTL() { +#ifdef HAVE_NTL+ return 1;+#else+ return 0;+#endif+}++extern "C" int have_GMP() { +#ifdef HAVE_GMP+ return 1;+#else+ return 0;+#endif+}++// -----------------------------------------------------------------------------+// config++extern "C"+void set_default_switches()+{+#ifdef HAVE_NTL+ // printf("we have NTL\n");+ On(SW_USE_CHINREM_GCD);+ On(SW_USE_NTL_SORT);+#endif+#ifdef HAVE_FLINT+ // printf("we have FLINT\n");+ #if defined(SW_USE_FL_GCD_P)+ On(SW_USE_FL_GCD_P); // apparently 4.0.3 (on Debian 9) does not yet have these...+ #endif+ #if defined(SW_USE_FL_GCD_0)+ On(SW_USE_FL_GCD_0);+ #endif+#endif+ On(SW_USE_EZGCD);+ On(SW_USE_EZGCD_P);+ On(SW_USE_QGCD);+}++// -----------------------------------------------------------------------------+// Variable++extern "C" +void free_var (Var *ptr)+{+ Variable *varp = (Variable*) ptr;+ delete varp;+}++extern "C" +Var *new_var_level(int level)+{+ Variable *varp = new Variable(level);+ return (void*)varp;+}++extern "C" +Var *new_var_name(char name)+{+ Variable *varp = new Variable(name);+ return (void*)varp;+}++extern "C" +Var *new_var_level_name(int level, char name)+{+ Variable *varp = new Variable(level,name);+ return (void*)varp;+}++extern "C" +Var *root_of(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ Variable *varp = new Variable( rootOf( *cfp ) );+ return (void*)varp;+}++// -------------------------------------++extern "C"+int get_var_level(Var *ptr)+{+ Variable *varp = (Variable*) ptr;+ return varp->level();+}++extern "C"+char get_var_name(Var *ptr)+{+ Variable *varp = (Variable*) ptr;+ return varp->name();+}++extern "C"+int has_mipo(Var *ptr)+{+ Variable *varp = (Variable*) ptr;+ return hasMipo( *varp );+}++extern "C"+CF *get_mipo(Var *ptr1 , Var *ptr2)+{+ Variable *varp1 = (Variable*) ptr1;+ Variable *varp2 = (Variable*) ptr2;+ CanonicalForm *cfp = new CanonicalForm( getMipo( *varp1 , *varp2 ) );+ return cfp;+}++extern "C"+void set_mipo(Var *ptr1 , CF *ptr2)+{+ Variable *varp = (Variable *) ptr1;+ CanonicalForm *cfp = (CanonicalForm*) ptr2;+ setMipo( *varp, *cfp );+}++extern "C"+void set_reduce(Var *ptr, int flag)+{+ Variable *varp = (Variable*) ptr;+ setReduce( *varp , flag);+}++// -----------------------------------------------------------------------------+// CanonicalForm++extern "C" +void free_cf (CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ delete cfp;+}++extern "C" +CF *copy_cf(CF *ptr)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr;+ CanonicalForm *cfp2 = new CanonicalForm(*cfp1);+ return (void*)cfp2;+}++// -----------------------------------------------------------------------------+// Factor++extern "C" +void free_fac (CFFactor *ptr)+{+ CFFactor *facp = (CFFactor*) ptr;+ delete facp;+}++extern "C" +Fac *copy_fac(Fac *ptr)+{+ CFFactor *facp1 = (CFFactor*) ptr;+ CFFactor *facp2 = new CFFactor(*facp1);+ return (void*)facp2;+}++extern "C" +int get_fac_expo(Fac *ptr)+{+ CFFactor *facp = (CFFactor*) ptr;+ return facp->exp();+}++extern "C" +CF *get_factor(Fac *ptr)+{+ CFFactor *facp = (CFFactor*) ptr;+ CanonicalForm *cfp = new CanonicalForm( facp->factor() );+ return (void*)cfp;+}++// -----------------------------------------------------------------------------+// Iterator++extern "C" +void free_iter(Iter *ptr)+{+ ListIterator<CFFactor> *iterp = (ListIterator<CFFactor> *) ptr;+ delete iterp;+}++extern "C"+Iter *next_iter(Iter *ptr)+{+ ListIterator<CFFactor> *iterp1 = (ListIterator<CFFactor> *) ptr;+ (*iterp1) ++; + return iterp1;+}++// -----------------------------------------------------------------------------+// List<Factor>++extern "C" +void free_faclist (FacList *ptr)+{+ CFFList *listp = (CFFList*) ptr;+ delete listp;+}++extern "C" +int get_list_length(FacList *ptr)+{+ CFFList *listp = (CFFList*) ptr;+ return listp->length();+}++extern "C" +void flatten_faclist (FacList *ptr, Fac **tgt_arr)+{+ CFFList *listp = (CFFList*) ptr;+ ListIterator<CFFactor> iter = ListIterator<CFFactor>(*listp);+ int n = listp->length();+ for(int i=0 ; i<n ; i++)+ {+ CFFactor *cffp = new CFFactor( iter.getItem() );+ tgt_arr[i] = (void*)cffp;+ iter++;+ }+}++// -----------------------------------------------------------------------------+// FACTORIZATION++extern "C" +FacList *hs_factorize (CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ CFFList *listp = new CFFList( factorize( *cfp ) ); + return (void*)listp;+}++// -------------------------------------++/* ++// factorize a multivariate polynomial over Q(alpha)+// (alpha can be 1???)+extern "C"+FacList *rat_factorize(CF *cfptr, Var *vptr, int substCheck)+{+ CanonicalForm *cfp = (CanonicalForm*) cfptr;+ Variable *alpha = (Variable*) vptr;+ CFFList *listp = new CFFList( RatFactorize( *cfp, *alpha, substCheck ) );+ return listp;+}++// factorize a multivariate polynomial over Fp+extern "C"+FacList *fp_factorize(CF *ptr, int substCheck)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ CFFList *listp = new CFFList( FpFactorize( *cfp, substCheck ) );+ return listp;+}++// factorize a multivariate polynomial over GF+extern "C"+FacList *gf_factorize(CF *ptr, int substCheck)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ CFFList *listp = new CFFList( GFFactorize( *cfp, substCheck ) );+ return listp;+}++// factorize a multivariate polynomial over F_p(alpha)+extern "C"+FacList *fq_factorize(CF *cfptr, Var *vptr, int substCheck)+{+ CanonicalForm *cfp = (CanonicalForm*) cfptr;+ Variable *alpha = (Variable*) vptr;+ CFFList *listp = new CFFList( FqFactorize( *cfp, *alpha, substCheck ) );+ return listp;+}+ +*/+ +// -----------------------------------------------------------------------------+// CanonicalForm++extern "C" +CF *empty_cf()+{+ CanonicalForm *cfp = new CanonicalForm();+ return (void*)cfp;+}++extern "C" +CF *const_cf(int kst)+{+ CanonicalForm *cfp = new CanonicalForm(kst);+ return (void*)cfp;+}++extern "C" +CF *var_cf(Var *var)+{+ Variable *varp = (Variable*)var;+ CanonicalForm *cfp = new CanonicalForm(*varp);+ return (void*)cfp;+}++extern "C" +CF *var_pow_cf(Var *var, int expo)+{+ Variable *varp = (Variable*)var;+ CanonicalForm *cfp = new CanonicalForm(*varp,expo);+ return (void*)cfp;+}++// -----------------------------------------------------------------------------+// some simple predicates++extern "C" +int is_zero(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->isZero());+}++extern "C" +int is_one(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->isOne());+}++extern "C" +int is_imm(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->isImm());+}++extern "C" +int is_univariate(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->isUnivariate());+}++// -----------------------------------------------------------------------------+// base domain predicates++extern "C" +int in_ZZ(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->inZ());+}++extern "C" +int in_QQ(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->inQ());+}++extern "C" +int in_GF(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->inGF());+}++extern "C" +int in_FF(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->inFF());+}++// -----------------------------------------------------------------------------+// domain predicates++extern "C" +int in_BaseDomain(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->inBaseDomain());+}++extern "C" +int in_CoeffDomain(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->inCoeffDomain());+}++extern "C" +int in_PolyDomain(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->inPolyDomain());+}++extern "C" +int in_Extension(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->inExtension());+}++extern "C" +int in_QuotDomain(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->inQuotDomain());+}++// -----------------------------------------------------------------------------+// imm_value, degree, level++extern "C" +long int smallint_value(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->intval()); // returns a long!!!+}++extern "C" +int degree_of(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->degree());+}++extern "C" +int level_of(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return (cfp->level());+}++extern "C" +Var *mvar_of(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ Variable *varp = new Variable( cfp->mvar() );+ return varp;+}++// -----------------------------------------------------------------------------++extern "C" +CF *index_poly(CF *ptr, int idx)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr;+ CanonicalForm *cfp2 = new CanonicalForm( (*cfp1)[idx] );+ return cfp2;+}++extern "C" +CF *map_into(CF *ptr)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr;+ CanonicalForm *cfp2 = new CanonicalForm( cfp1->mapinto() );+ return cfp2;+}++extern "C" +CF *substitute(CF *ptr1, Var *ptrv, CF *ptr2)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr1;+ Variable *varp = (Variable* ) ptrv;+ CanonicalForm *cfp2 = (CanonicalForm*) ptr2;+ CanonicalForm *cfp3 = new CanonicalForm( (*cfp1)( *cfp2 , *varp ) );+ return cfp3;+}++// -----------------------------------------------------------------------------+// numerator and denominator++extern "C" +CF *numer(CF *ptr)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr;+ CanonicalForm *cfp2 = new CanonicalForm( cfp1->num() );+ return cfp2;+}++extern "C" +CF *denom(CF *ptr)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr;+ CanonicalForm *cfp2 = new CanonicalForm( cfp1->den() );+ return cfp2;+}++// -----------------------------------------------------------------------------+// binary operations++extern "C" +int is_equal(CF *ptr1, CF* ptr2)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr1;+ CanonicalForm *cfp2 = (CanonicalForm*) ptr2; + return ( (*cfp1) == (*cfp2) );+}++extern "C" +CF *plus_cf(CF *ptr1, CF* ptr2)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr1;+ CanonicalForm *cfp2 = (CanonicalForm*) ptr2;+ CanonicalForm *cfp3 = new CanonicalForm( (*cfp1) + (*cfp2) );+ return cfp3;+}++extern "C" +CF *minus_cf(CF *ptr1, CF* ptr2)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr1;+ CanonicalForm *cfp2 = (CanonicalForm*) ptr2;+ CanonicalForm *cfp3 = new CanonicalForm( (*cfp1) - (*cfp2) );+ return cfp3;+}++extern "C" +CF *times_cf(CF *ptr1, CF* ptr2)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr1;+ CanonicalForm *cfp2 = (CanonicalForm*) ptr2;+ CanonicalForm *cfp3 = new CanonicalForm( (*cfp1) * (*cfp2) );+ return cfp3;+}++extern "C" +CF *pow_cf(CF *ptr1, int n)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr1;+ CanonicalForm *cfp3 = new CanonicalForm( power( *cfp1 , n ) );+ return cfp3;+}++extern "C" +CF *div_cf(CF *ptr1, CF* ptr2)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr1;+ CanonicalForm *cfp2 = (CanonicalForm*) ptr2;+ CanonicalForm *cfp3 = new CanonicalForm( div( *cfp1 , *cfp2 ) );+ return cfp3;+}++extern "C" +CF *mod_cf(CF *ptr1, CF* ptr2)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr1;+ CanonicalForm *cfp2 = (CanonicalForm*) ptr2;+ CanonicalForm *cfp3 = new CanonicalForm( mod( *cfp1 , *cfp2 ) );+ return cfp3;+}++extern "C" +CF *gcd_poly_cf(CF *ptr1, CF* ptr2)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr1;+ CanonicalForm *cfp2 = (CanonicalForm*) ptr2;+ CanonicalForm *cfp3 = new CanonicalForm( gcd_poly( *cfp1 , *cfp2 ) );+ return cfp3;+}++extern "C" +CF *reduce_cf(CF *ptr1, CF* ptr2)+{+ CanonicalForm *cfp1 = (CanonicalForm*) ptr1;+ CanonicalForm *cfp2 = (CanonicalForm*) ptr2;+ CanonicalForm *cfp3 = new CanonicalForm( reduce( *cfp1 , *cfp2 ) );+ return cfp3;+}++// -----------------------------------------------------------------------------+// GMP conversion++extern "C" +int get_gf_value(CF *ptr)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ return gf_value( *cfp );+}++extern "C" +void get_gmp_numerator(CF *ptr, mpz_ptr tgt)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ gmp_numerator( *cfp , tgt );+}++extern "C" +void get_gmp_denominator(CF *ptr, mpz_ptr tgt)+{+ CanonicalForm *cfp = (CanonicalForm*) ptr;+ gmp_denominator( *cfp , tgt );+}++extern "C" +CF *make_ZZ_from_gmp(mpz_srcptr src)+{+ mpz_t copy;+ mpz_init_set(copy,src);+ // make_cf DOES NOT COPY, just copies the header (mpz_t structure)...+ // ...so we have to copy it here because our src is ephemeral.+ CanonicalForm *cfp = new CanonicalForm( make_cf(copy) ); + return cfp;+}++extern "C" +CF *make_QQ_from_gmp(mpz_srcptr src1, mpz_srcptr src2, int normalize_flag )+{+ mpz_t copy1;+ mpz_t copy2;+ mpz_init_set(copy1,src1);+ mpz_init_set(copy2,src2);+ CanonicalForm *cfp = new CanonicalForm( make_cf( copy1 , copy2 , normalize_flag ) );+ return cfp;+}++extern "C" +CF *make_GF(int z)+{+ CanonicalForm *cfp = new CanonicalForm( make_cf_from_gf(z) );+ return cfp;+}+++/* +void gmp_numerator ( const CanonicalForm & f, mpz_ptr result );++void gmp_denominator ( const CanonicalForm & f, mpz_ptr result );++int gf_value (const CanonicalForm & f );++CanonicalForm make_cf ( const mpz_ptr n );++CanonicalForm make_cf ( const mpz_ptr n, const mpz_ptr d, bool normalize );++CanonicalForm make_cf_from_gf ( const int z );+*/+++// -----------------------------------------------------------------------------++extern "C"+int get_characteristic()+{+ return getCharacteristic();+}++// prime fields and QQ+extern "C"+void set_characteristic1(int c)+{+ setCharacteristic(c);+}++/*+// prime power fields (meaning FF?)+// apparently this does not exist anymore?!?!+extern "C"+void set_characteristic2(int c, int n)+{+ setCharacteristic(c,n);+}+*/++// Galois fields+extern "C"+void set_characteristic3(int c, int n, char var)+{+ setCharacteristic(c,n,var);+}++/*+// already defined above+extern "C"+int get_gf_value(CF *ptr) +{ + CanonicalForm *cfp = (CanonicalForm*) ptr;+ return gf_value( cfp );+}+*/++extern "C"+int is_FF_in_GF(CF *ptr) +{ + CanonicalForm *cfp = (CanonicalForm*) ptr;+ return cfp -> isFFinGF();+}++extern "C"+int get_GF_degree() +{ + return getGFDegree();+}++extern "C"+CF *get_GF_generator() +{ + return new CanonicalForm ( getGFGenerator() );+} +++// -----------------------------------------------------------------------------
+ singular-factory.cabal view
@@ -0,0 +1,82 @@+Name: singular-factory+Version: 0.1+Synopsis: Multivariate polynomial factorization via bindings to Singular-factory +Description: Bindings to Singular-factory. Factory is the subset of the Singular+ computer algebra system which does factorization of multivariate + polynomials (over integers, rationals, and finite fields)+License: GPL+License-file: LICENSE+Author: Balazs Komuves+Copyright: (c) 2019 Balazs Komuves+Maintainer: bkomuves (plus) hackage (at) gmail (dot) com+homepage: https://github.com/bkomuves/singular-factory+Stability: Experimental+Category: Math+Tested-With: GHC == 8.6.5+Cabal-Version: 2.0+Build-Type: Simple++Source-repository head+ type: git+ location: https://github.com/bkomuves/singular-factory++flag pkg-cfg-prefix+ description: whether the pkg-config factory package name has a prefix+ manual: False++--------------------------------------------------------------------------------+ +Library+ Build-Depends: base >= 4 && < 5, containers >= 0.5, text >= 1.0,+ filepath >= 1.0, directory >= 1.3, process >= 1.2, + hgmp >= 0.1.1+ + Exposed-Modules: Math.Singular.Factory+ Math.Singular.Factory.Domains+ Math.Singular.Factory.Variables+ Math.Singular.Factory.Polynomial+ Math.Singular.Factory.Expr+ Math.Singular.Factory.Parser+ Math.Singular.Factory.Counting+ Math.Singular.Factory.GFTables+ Math.Singular.Factory.Internal.CanonicalForm+ Math.Singular.Factory.Internal.Factory+ Math.Singular.Factory.Internal.DList+ + Default-Language: Haskell2010++ Default-extensions: BangPatterns, TypeSynonymInstances, FlexibleInstances, FlexibleContexts,+ KindSignatures, DataKinds, EmptyDataDecls, ScopedTypeVariables+ + Other-extensions: ForeignFunctionInterface, CPP, PatternSynonyms++ Hs-Source-Dirs: src+ + cc-options: -x c+++ c-sources: cpp_bits/interface.cpp+ extra-libraries: stdc++++ if flag(pkg-cfg-prefix)+ pkgconfig-depends: singular-factory+ else+ pkgconfig-depends: factory+ +--------------------------------------------------------------------------------++test-suite singular-factory-tests+ + type: exitcode-stdio-1.0+ + hs-source-dirs: test+ main-is: TestSuite.hs+ + build-depends: base >= 4 && < 5, random,+ singular-factory >= 0.1,+ QuickCheck >= 2,+ tasty, tasty-quickcheck, tasty-hunit++ Default-Language: Haskell2010+ Default-Extensions: CPP, BangPatterns+ +--------------------------------------------------------------------------------+
+ src/Math/Singular/Factory.hs view
@@ -0,0 +1,88 @@+{- |++Haskell bindings to the Singular-Factory multivariate polynomial factorization engine.++Singular is a computer algebra system developed at the University of Kaiserslautern, +and Factory is the polynomial factorization engine of Singular.++It handles multivariate polynomials over the integers, rationals, and finite fields+(and also algebraic and trancendental extensions of these, but those are not yet+supported).++Links: ++* Singular: https://www.singular.uni-kl.de/++* Factory: https://www.singular.uni-kl.de/dox/html/factory_page.html++-}++module Math.Singular.Factory+ ( -- * Initialization+ initialize+ -- * Configuration+ , factoryVersion + , factoryConfig , FactoryConfig(..)+ , printVersion+ , printConfig + -- * Re-exported modules+ , module Math.Singular.Factory.Domains+ , module Math.Singular.Factory.Variables+ , module Math.Singular.Factory.Polynomial+ ) + where++--------------------------------------------------------------------------------+ +import Math.Singular.Factory.Domains+import Math.Singular.Factory.Variables+import Math.Singular.Factory.Polynomial++import Math.Singular.Factory.GFTables+import Math.Singular.Factory.Internal.Factory+import Math.Singular.Factory.Internal.CanonicalForm++--------------------------------------------------------------------------------++-- | You are supposed to call 'initialize' before doing anything+-- (though factorization over characteristic zeros should work without it)+initialize = do+ initGFTables+ setDefaultSwitches++--------------------------------------------------------------------------------++data FactoryConfig = FactoryConfig+ { withFLINT :: Bool+ , withNTL :: Bool+ , withGMP :: Bool+ }+ deriving (Eq,Show)+ +factoryConfig :: FactoryConfig+factoryConfig = FactoryConfig+ { withFLINT = haveFLINT+ , withNTL = haveNTL+ , withGMP = haveGMP+ }+ +--------------------------------------------------------------------------------++-- | Prints factory\'s version+printVersion = do+ putStrLn $ "factory version = " ++ factoryVersion ++-- | Prints some more detailed configuration info+printConfig = do+ putStrLn $ "factory version = " ++ factoryVersion + putStrLn $ "package version = " ++ packageVersion + mb_gftables <- getGFTablesDir + putStrLn $ "gftables folder = " ++ show mb_gftables+ putStrLn $ "have FLINT = " ++ show haveFLINT+ putStrLn $ "have NTL = " ++ show haveNTL+ putStrLn $ "have GMP = " ++ show haveGMP+ +--------------------------------------------------------------------------------++ +
+ src/Math/Singular/Factory/Counting.hs view
@@ -0,0 +1,75 @@++-- | Brute-force counting of solutions of polynomial equations over (small) finite field++{-# LANGUAGE BangPatterns, TypeApplications, ScopedTypeVariables, DataKinds #-}+module Math.Singular.Factory.Counting where++--------------------------------------------------------------------------------++import Data.Proxy++import Math.Singular.Factory.Domains+import Math.Singular.Factory.Polynomial+import Math.Singular.Factory.GFTables++--------------------------------------------------------------------------------+-- * Hypersurfaces++-- | Count points of a hypersurface in an affine space+-- over a finite field.+--+-- The @Int@ input is the number of variables (that is, the dimension).+--+countAffineHypersurface :: FiniteDomain domain => Int -> Polynomial vars domain -> Int+countAffineHypersurface = go where+ go !1 !p = countTrues [ polyIsZero (substitute1 1 (konst a) p) | a <- enumerateDomain ] + go !k !p = sum [ go (k-1) (substitute1 k (konst a) p) | a <- enumerateDomain ]++-- | Count points of a hypersurface in an projective space+-- over a finite field.+-- +-- The @Int@ input is the number of /variables/ (that is, the dimension plus one)!+--+-- NOTE: We assume that the input is a homogeneous polynomial, but this is not checked!! +countProjectiveHypersurface :: FiniteDomain domain => Int -> Polynomial vars domain -> Int+countProjectiveHypersurface = go False where+ go !isPos !1 !p = countTrues [ polyIsZero $ substitute1 1 (konst a) p | a <- projEnumerateDomain isPos , let b = isPos || not (isZero a) , b ]+ go !isPos !k !p = sum [ go b (k-1) $ substitute1 k (konst a) p | a <- projEnumerateDomain isPos , let b = isPos || not (isZero a) ]+ +--------------------------------------------------------------------------------+-- * Systems of equations (varieties)++-- | Count solutions of a system of polynomial equations in an affine space+-- over a finite field.+--+-- The @Int@ input is the number of variables (that is, the dimension).+countAffineSolutions :: FiniteDomain domain => Int -> [Polynomial vars domain] -> Int+countAffineSolutions = go where+ go !1 !ps = countTrues [ and $ map polyIsZero $ map (substitute1 1 (konst a)) ps | a <- enumerateDomain ] + go !k !ps = sum [ go (k-1) $ map (substitute1 k (konst a)) ps | a <- enumerateDomain ]++-- | Count solutions of a system of polynomial equations in a projective space+-- over a finite field.+--+-- The @Int@ input is the number of /variables/ (that is, the dimension plus one)!+-- +-- NOTE: We assume that the input is a list of homogeneous polynomial, but this is not checked!! +countProjectiveSolutions :: FiniteDomain domain => Int -> [Polynomial vars domain] -> Int+countProjectiveSolutions = go False where+ go !isPos !1 !ps = countTrues [ and $ map polyIsZero $ map (substitute1 1 (konst a)) ps | a <- projEnumerateDomain isPos , let b = isPos || not (isZero a) , b ]+ go !isPos !k !ps = sum [ go b (k-1) $ map (substitute1 k (konst a)) ps | a <- projEnumerateDomain isPos , let b = isPos || not (isZero a) ]++--------------------------------------------------------------------------------+-- * Misc helpers++-- | if the input is False, return [0,1], otherwise all elements of the domain+projEnumerateDomain :: FiniteDomain domain => Bool -> [domain]+projEnumerateDomain True = enumerateDomain+projEnumerateDomain False = [0,1]++countTrues :: [Bool] -> Int+countTrues = foldr f 0 where+ f False !c = c+ f True !c = c+1+ +--------------------------------------------------------------------------------
+ src/Math/Singular/Factory/Domains.hs view
@@ -0,0 +1,324 @@++-- | Base domains.+--+-- These are the base rings and fields Factory can work with, namely:+--+-- * the ring integers+-- * the field of rationals+-- * finite fields (prime fields and Galois fields)+--+-- Another representation for finite fields are explicit algebraic extensions+-- of prime fields. This has less limitations (does not rely on precomputed+-- tables), but it is not implemented yet. +--+-- Note1: non-prime order Galois fields are supported only for small orders!+-- (this is a limitation by singular-factory). +-- Also for them to work, we need to be able to figure out the location of the +-- \"gftables\" directory first.+--+-- Note2: as Factory has the base domain as a global state (...), this whole +-- library is not at all thread safe!+--++{-# LANGUAGE + BangPatterns, PatternSynonyms, KindSignatures, DataKinds,+ FlexibleInstances, TypeSynonymInstances+ #-}+module Math.Singular.Factory.Domains where++--------------------------------------------------------------------------------++import Data.Ratio++import GHC.TypeLits+import Data.Proxy+import Data.IORef++import Control.Monad+import System.IO.Unsafe as Unsafe++import Math.Singular.Factory.Internal.CanonicalForm+import Math.Singular.Factory.Internal.Factory hiding ( FF , GF )++--------------------------------------------------------------------------------+-- * The global characteristics++type Prime = Int++data FactoryChar+ = CharZero -- ^ QQ+ | CharFp !Prime -- ^ prime field+ | CharGF !Prime !Int -- ^ Galois field+ deriving (Eq,Show)++-- | Unfortunately, Factory maintains a global state...+theFactoryChar :: IORef FactoryChar+theFactoryChar = Unsafe.unsafePerformIO $ newIORef CharZero++setFactoryChar :: FactoryChar -> IO ()+setFactoryChar new = do+ old <- readIORef theFactoryChar+ when (new /= old) $ do+ writeIORef theFactoryChar new+ case new of + CharZero -> setCharacteristic1 0 + CharFp p -> setCharacteristic1 p+ CharGF p n -> setCharacteristic3 p n '@' -- we use '@' for the Galois field variable for now++mapIntoCF :: FactoryChar -> CF -> CF+mapIntoCF char cf = Unsafe.unsafePerformIO $ do+ setFactoryChar char + mapIntoIO cf+ +--------------------------------------------------------------------------------+-- * Prime fields++-- | Haskell prime fields (this is provided only for completeness)+newtype Fp (p :: Nat) + = Fp Int + deriving (Eq)+ +fpPrime :: KnownNat p => Fp p -> Int+fpPrime = fromIntegral . natVal . proxyP where+ proxyP :: Fp p -> Proxy p+ proxyP _ = Proxy ++modp :: (KnownNat p, Integral a) => a -> Fp p+modp k = fp where+ fp = Fp $ mod (fromIntegral k) (fpPrime fp)++-- proxyFp :: Fp p -> Proxy p+-- proxyFp _ = Proxy++instance Show (Fp p) where+ show (Fp k) = show k++instance KnownNat p => Num (Fp p) where+ fromInteger = modp+ negate fp@(Fp k) = if k==0 then Fp 0 else Fp (fpPrime fp - k) + (Fp a) + (Fp b) = modp (a+b)+ (Fp a) - (Fp b) = modp (a-b)+ (Fp a) * (Fp b) = modp (a*b)+ abs = id+ signum = const (Fp 1)++fpToFF :: KnownNat p => Fp p -> FF p+fpToFF (Fp k) = mkFF k++--------------------------------------------------------------------------------+-- * Finite fields++-- | Factory prime fields+newtype FF (p :: Nat) + = FF { unFF :: CF }++mkFF :: (KnownNat p, Integral a) => a -> FF p +mkFF !k = ff where+ ff = Unsafe.unsafePerformIO $ do+ setBaseDomain (mkProxy ff)+ cf <- (mapIntoIO =<< makeIntegerCF (fromIntegral k))+ return (FF cf)+ +instance Eq (FF p) where + (FF a) == (FF b) = nativeEqCF a b++instance Show (FF p) where + show (FF cf) = show (valueFF cf) -- "[" ++ show (valueFF cf) ++ "]"++ffPrime :: KnownNat p => FF p -> Int+ffPrime = fromIntegral . natVal . proxyP where+ proxyP :: FF p -> Proxy p+ proxyP _ = Proxy++instance KnownNat p => Num (FF p) where+ fromInteger = mkFF+ negate (FF a) = FF (negate a)+ (FF a) + (FF b) = FF (a + b)+ (FF a) - (FF b) = FF (a - b)+ (FF a) * (FF b) = FF (a * b)+ abs = id+ signum = const 1++instance (KnownNat p) => Fractional (FF p) where+ fromRational q = mkFF (numerator q) / mkFF (denominator q)+ (FF a) / (FF b) = FF (divCF a b)+ +--------------------------------------------------------------------------------+-- * Galois fields++-- | Galois fields @GF(p^n)@. +--+-- The (nonzero) elements are represented as powers of the canonical generator.+--+-- The symbol is the name of the canonical generator (used for pretty-printing).+--+-- Note: because of how Factory is implemented, it is /required/ that @n >= 2@...+-- (use 'FF' for prime fields).+--+-- Also, the sizes are really limited (because they rely on tables, and only+-- small tables are included): @p < 256@ and @p^n < 65536@+--+newtype GF (p :: Nat) (n :: Nat) (x :: Symbol) + = GF { unGF :: CF }++-- | Create elements of the prime subfield. For the rest, you can use the+-- powers of the generator.+mkGF :: (KnownNat p, KnownNat n, KnownSymbol x, Integral a) => a -> GF p n x+mkGF !k = gf where+ gf = Unsafe.unsafePerformIO $ do+ setBaseDomain (mkProxy gf)+ cf <- (mapIntoIO =<< makeIntegerCF (fromIntegral k))+ return (GF cf)++-- | The canonical generator of the (multiplicative group of the) Galois field +genGF :: (KnownNat p, KnownNat n, KnownSymbol x) => GF p n x+genGF = gf where+ gf = Unsafe.unsafePerformIO $ do+ setBaseDomain (mkProxy gf)+ cf <- getGFGenerator+ return (GF cf)++-- | A power of the canonical generator +genPowGF :: (KnownNat p, KnownNat n, KnownSymbol x) => Int -> GF p n x+genPowGF e = powGF genGF e ++powGF :: (KnownNat p, KnownNat n, KnownSymbol x) => GF p n x -> Int -> GF p n x+powGF (GF cf) e = GF (powCF cf e)++instance Eq (GF p n x) where + (GF a) == (GF b) = nativeEqCF a b++instance (KnownNat p, KnownNat n, KnownSymbol x) => Show (GF p n x) where + show gf@(GF cf) = showGFValue1 (gfSymbol gf) (valueGF cf)++instance (KnownNat p, KnownNat n, KnownSymbol x) => Num (GF p n x) where+ fromInteger = mkGF+ negate (GF a) = GF (negate a)+ (GF a) + (GF b) = GF (a + b)+ (GF a) - (GF b) = GF (a - b)+ (GF a) * (GF b) = GF (a * b)+ abs = id+ signum = const 1+ +instance (KnownNat p, KnownNat n, KnownSymbol x) => Fractional (GF p n x) where+ fromRational q = mkGF (numerator q) / mkGF (denominator q)+ (GF a) / (GF b) = GF (divCF a b)++gfPrime :: KnownNat p => GF p n x -> Int+gfPrime = fromIntegral . natVal . proxyP where+ proxyP :: GF p n x -> Proxy p+ proxyP _ = Proxy+ +gfExponent :: KnownNat n => GF p n x -> Int+gfExponent = fromIntegral . natVal . proxyE where+ proxyE :: GF p n x -> Proxy n+ proxyE _ = Proxy+ +gfSymbol :: KnownSymbol x => GF p n x -> String+gfSymbol = symbolVal . proxyX where+ proxyX :: GF p n x -> Proxy x+ proxyX _ = Proxy++ +--------------------------------------------------------------------------------+-- * Base domains++class (Eq a, Show a, Num a) => BaseDomain a where+ characteristic :: Proxy a -> Int+ charExponent :: Proxy a -> Int + baseDomainName :: Proxy a -> String+ factoryChar :: Proxy a -> FactoryChar+ baseToCF :: a -> CF+ unsafeCfToBase :: CF -> a+ isZero :: a -> Bool+ isOne :: a -> Bool+ +setBaseDomain :: BaseDomain a => Proxy a -> IO ()+setBaseDomain = setFactoryChar . factoryChar ++instance BaseDomain Integer where+ characteristic _ = 0+ charExponent _ = 1+ baseDomainName _ = "ZZ"+ factoryChar _ = CharZero+ baseToCF x = Unsafe.unsafePerformIO (makeIntegerCF x)+ unsafeCfToBase = valueZZ+ isZero n = (n == 0)+ isOne n = (n == 1)+ +instance BaseDomain Rational where+ characteristic _ = 0+ charExponent _ = 1+ baseDomainName _ = "QQ"+ factoryChar _ = CharZero+ baseToCF x = Unsafe.unsafePerformIO (makeRationalCF x)+ unsafeCfToBase = valueQQ+ isZero q = (q == 0)+ isOne q = (q == 1)++instance KnownNat p => BaseDomain (Fp p) where+ characteristic pxy = (fpPrime $ proxyUndef pxy)+ charExponent _ = 1+ baseDomainName pxy = "F_" ++ show (characteristic pxy) + factoryChar pxy = CharFp (characteristic pxy)+ baseToCF x = baseToCF (fpToFF x)+ unsafeCfToBase cf = Fp (valueFF cf)+ isZero (Fp k) = (k == 0)+ isOne (Fp k) = (k == 1)+ +instance KnownNat p => BaseDomain (FF p) where+ characteristic pxy = (ffPrime $ proxyUndef pxy)+ charExponent pxy = 1+ baseDomainName pxy = "FF(" ++ show (characteristic pxy) ++ ")" where+ factoryChar pxy = CharFp (characteristic pxy) + baseToCF (FF cf) = cf+ unsafeCfToBase = FF+ isZero (FF cf) = isZeroCF cf+ isOne (FF cf) = isOneCF cf+ +instance (KnownNat p, KnownNat n, KnownSymbol x) => BaseDomain (GF p n x) where+ characteristic pxy = (gfPrime $ proxyUndef pxy)+ charExponent pxy = (gfExponent $ proxyUndef pxy)+ baseDomainName pxy = "GF(" ++ show (characteristic pxy) ++ ")" where+ factoryChar pxy = CharGF (characteristic pxy) (charExponent pxy)+ baseToCF (GF cf) = cf+ unsafeCfToBase = GF+ isZero (GF cf) = isZeroCF cf+ isOne (GF cf) = isOneCF cf++--------------------------------------------------------------------------------+-- * Finite domains++class BaseDomain domain => FiniteDomain domain where+ domainSize :: Proxy domain -> Int+ enumerateDomain :: [domain]+ +instance KnownNat p => FiniteDomain (Fp p) where+ domainSize pxy = characteristic pxy+ enumerateDomain = list where+ list = [ Fp i | i<-[0..p-1] ] + p = characteristic $ mkProxy (head list) ++instance KnownNat p => FiniteDomain (FF p) where+ domainSize pxy = characteristic pxy+ enumerateDomain = list where+ list = [ mkFF i | i<-[0..p-1] ] + p = characteristic $ mkProxy (head list) ++instance (KnownNat p, KnownNat n, KnownSymbol x) => FiniteDomain (GF p n x) where+ domainSize pxy = characteristic pxy ^ charExponent pxy+ enumerateDomain = list where+ list = 0 : [ genPowGF i | i<-[0..n-2] ] where+ pxy = mkProxy (head list) + n = domainSize pxy + +--------------------------------------------------------------------------------+-- * Proxy++mkProxy :: a -> Proxy a+mkProxy _ = Proxy++proxyUndef :: Proxy a -> a+proxyUndef _ = undefined++--------------------------------------------------------------------------------
+ src/Math/Singular/Factory/Expr.hs view
@@ -0,0 +1,111 @@++-- | Polynomial expressions (used for parsing)++{-# LANGUAGE BangPatterns, DeriveFunctor, DeriveFoldable, DeriveTraversable #-}+module Math.Singular.Factory.Expr where++--------------------------------------------------------------------------------++import Data.Char+import Data.List++import Control.Applicative+import Control.Monad++import Data.Text.Lazy ( Text )+import qualified Data.Text.Lazy as T+import qualified Data.Text.Lazy.Read as T++import Math.Singular.Factory.Internal.DList as DList++--------------------------------------------------------------------------------+-- * Types++data Sign + = Plus + | Minus + deriving (Eq,Ord,Show)++negateIfMinus :: Num a => Sign -> a -> a+negateIfMinus Plus = id+negateIfMinus Minus = negate++--------------------------------------------------------------------------------++-- | Monomials+newtype Monom var + = Monom [(var,Int)]+ deriving (Eq,Ord,Show,Functor,Foldable,Traversable)++-- | A monomial multiplied by a constant+data Term coeff var + = Term !coeff !(Monom var) + deriving (Eq,Ord,Show,Functor,Foldable,Traversable)+ +-- | Polynomials as linear combination of monomials+newtype GenPoly coeff var + = GenPoly [Term coeff var]+ deriving (Eq,Ord,Show,Functor,Foldable,Traversable)++-- | Polynomial expressions+data Expr v+ = VarE !v+ | KstE !Integer+ | NegE (Expr v)+ | LinE [(Sign,Expr v)]+ | MulE [Expr v]+ | PowE (Expr v) !Int+ deriving (Eq,Ord,Show,Functor,Foldable,Traversable)++--------------------------------------------------------------------------------+-- * Evaluation to @Num@++evalSign :: Num c => Sign -> c -> c+evalSign Plus = id+evalSign Minus = negate++evalMonom :: Num c => (var -> c) -> Monom var -> c+evalMonom f (Monom list) = product (map g list) where+ g (var,expo) = (f var)^expo++evalTerm :: Num c => (coeff -> c) -> (var -> c) -> Term coeff var -> c+evalTerm f g (Term coeff monom) = f coeff * evalMonom g monom ++evalGenPoly :: Num c => (coeff -> c) -> (var -> c) -> GenPoly coeff var -> c+evalGenPoly f g (GenPoly terms) = sum (map (evalTerm f g) terms)+ +evalExpr :: Num c => (var -> c) -> Expr var -> c+evalExpr evalVar = go where+ go expr = case expr of+ VarE v -> evalVar v+ KstE k -> fromInteger k+ NegE e -> negate (go e)+ LinE xs -> sum [ evalSign pm (go x) | (pm,x) <- xs ]+ MulE xs -> product (map go xs)+ PowE e k -> (go e)^k+ +--------------------------------------------------------------------------------++{-++prettExpr :: Expr -> String+prettExpr expr = DList.toList (prettPrecExpr 0 expr)++prettyPrecExpr :: Int -> Expr -> DList Char+prettyPrecExpr = go where++ chr c = DList.singleton c+ str s = DList.append s++ go !prec !expr = case expr of+ VarE !Var+ KstE !Integer+ NegE Expr+ LinE [(Sign,Expr)]+ MulE [Expr]+ PowE Expr !Int++-}++--------------------------------------------------------------------------------+
+ src/Math/Singular/Factory/GFTables.hs view
@@ -0,0 +1,145 @@++-- | Guessing the location of factory\'s gftables.+--+-- For the Galois field domains to work (for non-primer order), you have to+-- first initialize singular-factory by setting this directory.+--+-- This can be done either by `initGFTables` or `initGFTables'`.+--++{-# LANGUAGE CPP, BangPatterns, ForeignFunctionInterface #-}+module Math.Singular.Factory.GFTables where++------------------------------------------------------------------------------------------++import Control.Monad++import Foreign.Ptr+import Foreign.C+import Foreign.C.String++import System.FilePath+import System.Directory+import System.Process++import Data.IORef+import System.IO.Unsafe as Unsafe++--------------------------------------------------------------------------------+-- * A global variable++{-# NOINLINE theGFTablesDir #-}+theGFTablesDir :: IORef (Maybe FilePath)+theGFTablesDir = Unsafe.unsafePerformIO $ newIORef Nothing ++getGFTablesDir :: IO (Maybe FilePath)+getGFTablesDir = readIORef theGFTablesDir++--------------------------------------------------------------------------------+-- * Initialization++-- | We try to guess the location.+initGFTables :: IO ()+initGFTables = initGFTables' Nothing++-- | Set the location of the small finite field table files.+--+-- If you know where they are located, please set it.+-- If you don't know, we try to guess it, but I have no idea how+-- to figure this out in general (pkg-config does not seem to have this information...)+--+initGFTables' :: Maybe FilePath -> IO ()+initGFTables' mbdir = case mbdir of+ Just fpath -> setGFTablesDir fpath+ Nothing -> guessGFTablesDir >>= \d -> case d of+ Just fpath -> do + -- putStrLn $ "gftables dir = " ++ (fpath </> "gftables")+ setGFTablesDir fpath+ Nothing -> do+ writeIORef theGFTablesDir Nothing+ putStrLn "WARNING: cannot find factory's gftables"++setGFTablesDir :: FilePath -> IO ()+setGFTablesDir fpath0 = do+ fpath1 <- canonicalizePath fpath0+ withCString (fpath1 ++ "/") $ \ptr -> set_gftable_dir ptr+ writeIORef theGFTablesDir (Just fpath1)+ +-- | Apparently we need to manually find the directory containing the GF tables...+--+-- On my debian install it is at @\/usr\/share\/singular\/factory\/gftables\/@, but how+-- to figure that out???+foreign import ccall "set_gftable_dir" set_gftable_dir :: Ptr CChar -> IO ()++------------------------------------------------------------------------------------------+-- * Guessing++guessGFTablesDir :: IO (Maybe FilePath)+guessGFTablesDir = do++#if defined(linux_HOST_OS)+ guessLinux+#elif defined(darwin_HOST_OS)+ guessHomebrew+#elif defined(mingw32_HOST_OS) || defined(mingw64_HOST_OS) + guessCygwin+#else+ return Nothing+#endif+ +------------------------------------------------------------------------------------------++infixr 5 >>>++(>>>) :: IO (Maybe a) -> IO (Maybe a) -> IO (Maybe a) +(>>>) action1 action2 = do + mb <- action1 + case mb of + Just x -> return (Just x)+ Nothing -> action2+ +testDir :: FilePath -> IO (Maybe FilePath)+testDir dir = doesFileExist (dir </> "gftables/361") >>= \b -> if b + then return (Just dir) + else return Nothing++------------------------------------------------------------------------------------------++-- macOS w/ Homebrew+-- on my machine it looks like this: /usr/local/Cellar/singular/4.1.2p1_2/share/factory+guessHomebrew :: IO (Maybe FilePath)+guessHomebrew = do+ let brew_prefix = "/usr/local" -- TODO: maybe use "brew config" (but it's rather slow)+ let cellar = brew_prefix </> "Cellar"+ let sing_root = cellar </> "singular"+ entries <- map (sing_root </>) <$> listDirectory sing_root+ subdirs <- filterM doesDirectoryExist entries+ -- print entries+ -- print subdirs+ foldl (>>>) (return Nothing) [ testDir (sing_root </> d </> "share/factory") | d <- subdirs]++-- generic Linux+-- I guess typically it looks like this:+guessLinux :: IO (Maybe FilePath)+guessLinux =+ testDir "/usr/share/singular/factory" >>>+ testDir "/usr/share/singular" >>>+ testDir "/usr/share/factory" >>>+ testDir "/usr/local/share/singular/factory" >>>+ testDir "/usr/local/share/singular" >>>+ testDir "/usr/local/share/factory" ++-- cygwin+guessCygwin ::IO (Maybe FilePath)+guessCygwin = do+ cygwin_root <- readCreateProcess (shell "cygpath -w /") ""+ let test1 dir = testDir (cygwin_root </> dir)+ id <$>+ test1 "/usr/share/singular/factory" >>>+ test1 "/usr/share/singular" >>>+ test1 "/usr/share/factory" >>>+ test1 "/usr/local/share/singular/factory" >>>+ test1 "/usr/local/share/singular" >>>+ test1 "/usr/local/share/factory" ++------------------------------------------------------------------------------------------
+ src/Math/Singular/Factory/Internal/CanonicalForm.hs view
@@ -0,0 +1,511 @@++-- | Low-level bindings to singular-factory++{-# LANGUAGE BangPatterns, EmptyDataDecls, ForeignFunctionInterface #-}+module Math.Singular.Factory.Internal.CanonicalForm where++--------------------------------------------------------------------------------++import Data.Word+import Data.Ratio++import Foreign.C+import Foreign.Ptr+import Foreign.ForeignPtr+import Foreign.Marshal.Array++import Numeric.GMP.Types+import qualified Numeric.GMP.Utils as GMP ++--------------------------------------------------------------------------------+-- * types++data Variable+data CanonicalForm+data Factor -- CFFactor+data FactorList -- List<CFFactor>++type Var = ForeignPtr Variable+type CF = ForeignPtr CanonicalForm+type Fac = ForeignPtr Factor+type FacList = ForeignPtr FactorList++--------------------------------------------------------------------------------+-- * constants++foreign import ccall "level_trans" c_level_trans :: CInt +foreign import ccall "level_base" c_level_base :: CInt +foreign import ccall "level_quot" c_level_quot :: CInt +foreign import ccall "level_expr" c_level_expr :: CInt ++--------------------------------------------------------------------------------+-- * versions++foreign import ccall "get_factory_version" c_get_factory_version :: Ptr CChar -> Int -> IO ()+foreign import ccall "get_package_version" c_get_package_version :: Ptr CChar -> Int -> IO ()++getFactoryVersion :: IO String+getFactoryVersion = do+ let n = 16+ allocaArray n $ \ptr -> do+ c_get_factory_version ptr n+ peekCString ptr++getPackageVersion :: IO String+getPackageVersion = do+ let n = 16+ allocaArray n $ \ptr -> do+ c_get_package_version ptr n+ peekCString ptr++foreign import ccall "have_FLINT" c_have_FLINT :: IO CInt+foreign import ccall "have_NTL" c_have_NTL :: IO CInt+foreign import ccall "have_GMP" c_have_GMP :: IO CInt++--------------------------------------------------------------------------------+-- * config++foreign import ccall "set_default_switches" c_set_default_switches :: IO ()++setDefaultSwitches :: IO ()+setDefaultSwitches = do+ c_set_default_switches+ +--------------------------------------------------------------------------------+-- * memory management++foreign import ccall "&free_var"+ varFinalizerPtr :: FunPtr (Ptr Variable -> IO ()) ++foreign import ccall "&free_cf"+ cfFinalizerPtr :: FunPtr (Ptr CanonicalForm -> IO ()) ++foreign import ccall "&free_fac"+ facFinalizerPtr :: FunPtr (Ptr Factor -> IO ()) ++foreign import ccall "&free_faclist"+ faclistFinalizerPtr :: FunPtr (Ptr FactorList -> IO ()) ++makeVar :: Ptr Variable -> IO Var+makeVar = newForeignPtr varFinalizerPtr++makeCF :: Ptr CanonicalForm -> IO CF+makeCF = newForeignPtr cfFinalizerPtr++makeFac :: Ptr Factor -> IO Fac+makeFac = newForeignPtr facFinalizerPtr++makeFacList :: Ptr FactorList -> IO FacList+makeFacList = newForeignPtr faclistFinalizerPtr++--------------------------------------------------------------------------------+-- * variables++foreign import ccall "new_var_level" c_new_var_level :: CInt -> IO (Ptr Variable)+foreign import ccall "new_var_name" c_new_var_name :: CChar -> IO (Ptr Variable)+foreign import ccall "new_var_level_name" c_new_var_level_name :: CInt -> CChar -> IO (Ptr Variable)++newVarL :: Int -> IO Var+newVarL level = makeVar =<< c_new_var_level (fromIntegral level)++newVarN :: Char -> IO Var+newVarN name = makeVar =<< c_new_var_name (castCharToCChar name)++newVarLN :: Int -> Char -> IO Var+newVarLN level name = makeVar =<< c_new_var_level_name (fromIntegral level) (castCharToCChar name)++newTransVar :: IO Var+newTransVar = makeVar =<< c_new_var_level (c_level_trans)++foreign import ccall "root_of" c_root_of :: Ptr CanonicalForm -> IO (Ptr Variable)++newRootOf :: CF -> IO Var+newRootOf cf = withForeignPtr cf $ \ptr -> makeVar =<< c_root_of ptr++foreign import ccall "get_var_level" c_get_var_level :: Ptr Variable -> IO CInt+foreign import ccall "get_var_name" c_get_var_name :: Ptr Variable -> IO CChar++getVarLevel :: Var -> IO Int+getVarLevel var = withForeignPtr var $ \ptr -> fromIntegral <$> (c_get_var_level ptr)++getVarName :: Var -> IO Char+getVarName var = withForeignPtr var $ \ptr -> castCCharToChar <$> (c_get_var_name ptr)++foreign import ccall "has_mipo" c_has_mipo :: Ptr Variable -> IO CInt+foreign import ccall "get_mipo" c_get_mipo :: Ptr Variable -> Ptr Variable -> IO (Ptr CanonicalForm)+foreign import ccall "set_mipo" c_set_mipo :: Ptr Variable -> Ptr CanonicalForm -> IO ()+foreign import ccall "set_reduce" c_set_reduce :: Ptr Variable -> CInt -> IO ()++hasMinimalPoly :: Var -> IO Bool+hasMinimalPoly var = withForeignPtr var $ \ptr -> liftBool (c_has_mipo ptr)++getMinimalPoly :: Var -> Var -> IO CF+getMinimalPoly var1 var2 = + withForeignPtr var1 $ \ptr1 -> + withForeignPtr var2 $ \ptr2 -> + makeCF =<< c_get_mipo ptr1 ptr2++setReduceFlag :: Var -> Bool -> IO ()+setReduceFlag var flag = withForeignPtr var $ \ptr -> c_set_reduce ptr (if flag then 1 else 0)++--------------------------------------------------------------------------------+-- * factors++foreign import ccall "get_factor" c_get_factor :: Ptr Factor -> IO (Ptr CanonicalForm)++getFactorCF :: Fac -> IO CF+getFactorCF fac = withForeignPtr fac $ \ptr -> makeCF =<< c_get_factor ptr++foreign import ccall "get_fac_expo" c_get_fac_expo :: Ptr Factor -> IO CInt++getFactorExpo :: Fac -> IO Int+getFactorExpo fac = withForeignPtr fac $ \ptr -> fromIntegral <$> c_get_fac_expo ptr++unpackFactor :: Fac -> IO (CF,Int)+unpackFactor fac = do+ cf <- getFactorCF fac+ expo <- getFactorExpo fac+ return (cf,expo)++--------------------------------------------------------------------------------+-- * lists++foreign import ccall "get_list_length" c_get_list_length :: Ptr FactorList -> IO CInt++getListLength :: FacList -> IO Int+getListLength faclist = withForeignPtr faclist $ \ptr -> fromIntegral <$> c_get_list_length ptr++--------------------------------------------------------------------------------+-- * factorization++foreign import ccall "flatten_faclist" c_flatten_faclist :: Ptr FactorList -> Ptr (Ptr Factor) -> IO ()++flattenFactorList :: FacList -> IO [Fac]+flattenFactorList faclist = withForeignPtr faclist $ \listptr -> do+ n <- fromIntegral <$> c_get_list_length listptr+ allocaArray n $ \arrptr -> do+ c_flatten_faclist listptr arrptr+ facptrs <- peekArray n arrptr+ mapM makeFac facptrs++unpackFactorList :: FacList -> IO [(CF,Int)]+unpackFactorList faclist = mapM unpackFactor =<< flattenFactorList faclist++foreign import ccall "hs_factorize" c_hs_factorize :: Ptr CanonicalForm -> IO (Ptr FactorList)++factorizeIO' :: CF -> IO FacList+factorizeIO' cf = withForeignPtr cf $ \ptr -> makeFacList =<< (c_hs_factorize ptr)++factorizeIO :: CF -> IO [(CF,Int)]+factorizeIO cf = unpackFactorList =<< factorizeIO' cf++{-+foreign import ccall "rat_factorize" c_rat_factorize :: Ptr CanonicalForm -> Ptr Variable -> CInt -> IO (Ptr FactorList)+foreign import ccall "fq_factorize" c_fq_factorize :: Ptr CanonicalForm -> Ptr Variable -> CInt -> IO (Ptr FactorList)+foreign import ccall "fp_factorize" c_fp_factorize :: Ptr CanonicalForm -> CInt -> IO (Ptr FactorList)+foreign import ccall "gf_factorize" c_gf_factorize :: Ptr CanonicalForm -> CInt -> IO (Ptr FactorList)++fpFactorizeIO' :: CF -> Bool -> IO FacList+fpFactorizeIO' cf subst_check_flag = + withForeignPtr cf $ \ptr -> + makeFacList =<< (c_fp_factorize ptr (bool2cint subst_check_flag))++gfFactorizeIO' :: CF -> Bool -> IO FacList+gfFactorizeIO' cf subst_check_flag = + withForeignPtr cf $ \ptr -> + makeFacList =<< (c_gf_factorize ptr (bool2cint subst_check_flag))++ratFactorizeIO' :: CF -> Var -> Bool -> IO FacList+ratFactorizeIO' cf var subst_check_flag = + withForeignPtr cf $ \ptr -> withForeignPtr var $ \varptr -> + makeFacList =<< (c_rat_factorize ptr varptr (bool2cint subst_check_flag))++fqFactorizeIO' :: CF -> Var -> Bool -> IO FacList+fqFactorizeIO' cf var subst_check_flag = + withForeignPtr cf $ \ptr -> withForeignPtr var $ \varptr -> + makeFacList =<< (c_fq_factorize ptr varptr (bool2cint subst_check_flag))++fpFactorizeIO :: CF -> Bool -> IO [(CF,Int)]+fpFactorizeIO cf flag = unpackFactorList =<< fpFactorizeIO' cf flag++gfFactorizeIO :: CF -> Bool -> IO [(CF,Int)]+gfFactorizeIO cf flag = unpackFactorList =<< gfFactorizeIO' cf flag++ratFactorizeIO :: CF -> Var -> Bool -> IO [(CF,Int)]+ratFactorizeIO cf var flag = unpackFactorList =<< ratFactorizeIO' cf var flag ++fqFactorizeIO :: CF -> Var -> Bool -> IO [(CF,Int)]+fqFactorizeIO cf var flag = unpackFactorList =<< fqFactorizeIO' cf var flag +-}++--------------------------------------------------------------------------------+-- * basic CFs++foreign import ccall "empty_cf" c_empty_cf :: IO (Ptr CanonicalForm)+ +newEmptyCF :: IO CF+newEmptyCF = makeCF =<< c_empty_cf++foreign import ccall "const_cf" c_const_cf :: CInt -> IO (Ptr CanonicalForm)+ +newSmallConstCF :: Int -> IO CF+newSmallConstCF k = makeCF =<< c_const_cf (fromIntegral k)++foreign import ccall "var_cf" c_var_cf :: Ptr Variable -> IO (Ptr CanonicalForm)+foreign import ccall "var_pow_cf" c_var_pow_cf :: Ptr Variable -> Int -> IO (Ptr CanonicalForm)++varIO :: Var -> IO CF+varIO var = withForeignPtr var $ \vptr -> makeCF =<< c_var_cf vptr++varPowIO :: Var -> Int -> IO CF+varPowIO var expo = withForeignPtr var $ \vptr -> makeCF =<< c_var_pow_cf vptr expo++--------------------------------------------------------------------------------+-- * basic CF predicates++bool2cint :: Bool -> CInt+bool2cint True = 1+bool2cint False = 0++cint2bool :: CInt -> Bool+cint2bool k = (k/=0)++liftBool :: IO CInt -> IO Bool+liftBool action = action >>= \k -> return (cint2bool k)++----------------------------------------++foreign import ccall "is_zero" c_is_zero :: Ptr CanonicalForm -> IO CInt+foreign import ccall "is_one" c_is_one :: Ptr CanonicalForm -> IO CInt++isZeroIO :: CF -> IO Bool+isZeroIO cf = withForeignPtr cf $ \ptr -> liftBool (c_is_zero ptr)++isOneIO :: CF -> IO Bool+isOneIO cf = withForeignPtr cf $ \ptr -> liftBool (c_is_one ptr)++foreign import ccall "is_imm" c_is_imm :: Ptr CanonicalForm -> IO CInt+foreign import ccall "is_univariate" c_is_univariate :: Ptr CanonicalForm -> IO CInt++isImmediateIO :: CF -> IO Bool+isImmediateIO cf = withForeignPtr cf $ \ptr -> liftBool (c_is_imm ptr)++isUnivariateIO :: CF -> IO Bool+isUnivariateIO cf = withForeignPtr cf $ \ptr -> liftBool (c_is_univariate ptr)++foreign import ccall "in_ZZ" c_in_ZZ :: Ptr CanonicalForm -> IO CInt+foreign import ccall "in_QQ" c_in_QQ :: Ptr CanonicalForm -> IO CInt+foreign import ccall "in_GF" c_in_GF :: Ptr CanonicalForm -> IO CInt+foreign import ccall "in_FF" c_in_FF :: Ptr CanonicalForm -> IO CInt++isInZZ_IO :: CF -> IO Bool+isInZZ_IO cf = withForeignPtr cf $ \ptr -> liftBool (c_in_ZZ ptr)++isInQQ_IO :: CF -> IO Bool+isInQQ_IO cf = withForeignPtr cf $ \ptr -> liftBool (c_in_QQ ptr)++isInGF_IO :: CF -> IO Bool+isInGF_IO cf = withForeignPtr cf $ \ptr -> liftBool (c_in_GF ptr)++isInFF_IO :: CF -> IO Bool+isInFF_IO cf = withForeignPtr cf $ \ptr -> liftBool (c_in_FF ptr)++foreign import ccall "in_BaseDomain" c_in_BaseDomain :: Ptr CanonicalForm -> IO CInt+foreign import ccall "in_CoeffDomain" c_in_CoeffDomain :: Ptr CanonicalForm -> IO CInt+foreign import ccall "in_PolyDomain" c_in_PolyDomain :: Ptr CanonicalForm -> IO CInt+foreign import ccall "in_Extension" c_in_Extension :: Ptr CanonicalForm -> IO CInt+foreign import ccall "in_QuotDomain" c_in_QuotDomain :: Ptr CanonicalForm -> IO CInt++isInBaseDomainIO :: CF -> IO Bool+isInBaseDomainIO cf = withForeignPtr cf $ \ptr -> liftBool (c_in_BaseDomain ptr)++isInCoeffDomainIO :: CF -> IO Bool+isInCoeffDomainIO cf = withForeignPtr cf $ \ptr -> liftBool (c_in_CoeffDomain ptr)++isInPolyDomainIO :: CF -> IO Bool+isInPolyDomainIO cf = withForeignPtr cf $ \ptr -> liftBool (c_in_PolyDomain ptr)++isInExtensionIO :: CF -> IO Bool+isInExtensionIO cf = withForeignPtr cf $ \ptr -> liftBool (c_in_Extension ptr)++isInQuotDomainIO :: CF -> IO Bool+isInQuotDomainIO cf = withForeignPtr cf $ \ptr -> liftBool (c_in_QuotDomain ptr)++--------------------------------------------------------------------------------+-- * basic properties++foreign import ccall "degree_of" c_degree_of :: Ptr CanonicalForm -> IO CInt+foreign import ccall "level_of" c_level_of :: Ptr CanonicalForm -> IO CInt+foreign import ccall "mvar_of" c_mvar_of :: Ptr CanonicalForm -> IO (Ptr Variable)++getDegree :: CF -> IO Int+getDegree cf = withForeignPtr cf $ \ptr -> fromIntegral <$> (c_degree_of ptr)++getLevel :: CF -> IO Int+getLevel cf = withForeignPtr cf $ \ptr -> fromIntegral <$> (c_level_of ptr)++getMainVar :: CF -> IO Var+getMainVar cf = withForeignPtr cf $ \ptr -> makeVar =<< (c_mvar_of ptr)++--------------------------------------------------------------------------------+-- * small values++foreign import ccall "smallint_value" c_smallint_value :: Ptr CanonicalForm -> IO CLong -- !!!++getSmallIntValue :: CF -> IO Int+getSmallIntValue cf = withForeignPtr cf $ \ptr -> fromIntegral <$> (c_smallint_value ptr)++foreign import ccall "numer" c_numer :: Ptr CanonicalForm -> IO (Ptr CanonicalForm)+foreign import ccall "denom" c_denom :: Ptr CanonicalForm -> IO (Ptr CanonicalForm)++getNumer :: CF -> IO CF+getNumer cf = withForeignPtr cf $ \ptr -> makeCF =<< (c_numer ptr)++getDenom :: CF -> IO CF+getDenom cf = withForeignPtr cf $ \ptr -> makeCF =<< (c_denom ptr)++foreign import ccall "index_poly" c_index_poly :: Ptr CanonicalForm -> Int -> IO (Ptr CanonicalForm)+foreign import ccall "map_into" c_map_into :: Ptr CanonicalForm -> IO (Ptr CanonicalForm)+foreign import ccall "substitute" c_substitute :: Ptr CanonicalForm -> Ptr Variable -> Ptr CanonicalForm -> IO (Ptr CanonicalForm)++--------------------------------------------------------------------------------+-- * Polynomial operations++-- | Get the given degree part+getCfAtIndex :: CF -> Int -> IO CF+getCfAtIndex cf idx = withForeignPtr cf $ \ptr -> makeCF =<< (c_index_poly ptr $ fromIntegral idx)++-- | Map into the current base domain+mapIntoIO :: CF -> IO CF+mapIntoIO cf = withForeignPtr cf $ \ptr -> makeCF =<< (c_map_into ptr)++-- | Map into the current base domain+substituteIO :: Var -> CF -> (CF -> IO CF)+substituteIO var what cf = + withForeignPtr var $ \pvar -> + withForeignPtr what $ \pwhat -> + withForeignPtr cf $ \pcf -> + makeCF =<< (c_substitute pcf pvar pwhat)++--------------------------------------------------------------------------------+-- * Binary operations++foreign import ccall "is_equal" c_is_equal :: Ptr CanonicalForm -> Ptr CanonicalForm -> IO CInt++isEqualIO :: CF -> CF -> IO Bool+isEqualIO x y = withForeignPtr x $ \p -> withForeignPtr y $ \q -> liftBool (c_is_equal p q)++foreign import ccall "plus_cf" c_plus_cf :: Ptr CanonicalForm -> Ptr CanonicalForm -> IO (Ptr CanonicalForm)+foreign import ccall "minus_cf" c_minus_cf :: Ptr CanonicalForm -> Ptr CanonicalForm -> IO (Ptr CanonicalForm)+foreign import ccall "times_cf" c_times_cf :: Ptr CanonicalForm -> Ptr CanonicalForm -> IO (Ptr CanonicalForm)+foreign import ccall "pow_cf" c_pow_cf :: Ptr CanonicalForm -> CInt -> IO (Ptr CanonicalForm)+foreign import ccall "div_cf" c_div_cf :: Ptr CanonicalForm -> Ptr CanonicalForm -> IO (Ptr CanonicalForm)+foreign import ccall "mod_cf" c_mod_cf :: Ptr CanonicalForm -> Ptr CanonicalForm -> IO (Ptr CanonicalForm)++foreign import ccall "gcd_poly_cf" c_gcd_poly_cf :: Ptr CanonicalForm -> Ptr CanonicalForm -> IO (Ptr CanonicalForm)+foreign import ccall "reduce_cf" c_reduce_cf :: Ptr CanonicalForm -> Ptr CanonicalForm -> IO (Ptr CanonicalForm)++plusIO :: CF -> CF -> IO CF+plusIO x y = withForeignPtr x $ \p -> withForeignPtr y $ \q -> makeCF =<< (c_plus_cf p q)++minusIO :: CF -> CF -> IO CF+minusIO x y = withForeignPtr x $ \p -> withForeignPtr y $ \q -> makeCF =<< (c_minus_cf p q)++timesIO :: CF -> CF -> IO CF+timesIO x y = withForeignPtr x $ \p -> withForeignPtr y $ \q -> makeCF =<< (c_times_cf p q)++powIO :: CF -> Int -> IO CF+powIO x n = withForeignPtr x $ \p -> makeCF =<< (c_pow_cf p $ fromIntegral n)++divIO :: CF -> CF -> IO CF+divIO x y = withForeignPtr x $ \p -> withForeignPtr y $ \q -> makeCF =<< (c_div_cf p q)++modIO :: CF -> CF -> IO CF+modIO x y = withForeignPtr x $ \p -> withForeignPtr y $ \q -> makeCF =<< (c_mod_cf p q)++gcdPolyIO :: CF -> CF -> IO CF+gcdPolyIO x y = withForeignPtr x $ \p -> withForeignPtr y $ \q -> makeCF =<< (c_gcd_poly_cf p q)++reduceIO :: CF -> CF -> IO CF+reduceIO x y = withForeignPtr x $ \p -> withForeignPtr y $ \q -> makeCF =<< (c_reduce_cf p q)++--------------------------------------------------------------------------------+-- * GMP compatibility layer++foreign import ccall "get_gmp_numerator" c_get_gmp_numerator :: Ptr CanonicalForm -> Ptr MPZ -> IO ()+foreign import ccall "get_gmp_denominator" c_get_gmp_denominator :: Ptr CanonicalForm -> Ptr MPZ -> IO ()++getGmpNumerator :: CF -> IO Integer+getGmpNumerator cf =+ withForeignPtr cf $ \cfp -> + GMP.withOutInteger_ (\mpz_ptr -> c_get_gmp_numerator cfp mpz_ptr)++getGmpDenominator :: CF -> IO Integer+getGmpDenominator cf =+ withForeignPtr cf $ \cfp -> + GMP.withOutInteger_ (\mpz_ptr -> c_get_gmp_denominator cfp mpz_ptr)++foreign import ccall "make_ZZ_from_gmp" c_make_ZZ_from_gmp :: Ptr MPZ -> IO (Ptr CanonicalForm)+foreign import ccall "make_QQ_from_gmp" c_make_QQ_from_gmp :: Ptr MPZ -> Ptr MPZ -> CInt -> IO (Ptr CanonicalForm)++makeIntegerCF :: Integer -> IO CF+makeIntegerCF n = + GMP.withInInteger n $ \mpz_ptr -> + makeCF =<< (c_make_ZZ_from_gmp mpz_ptr)++makeRationalCF :: Rational -> IO CF+makeRationalCF n = + GMP.withInInteger (numerator n) $ \mpz_ptr1 -> + GMP.withInInteger (denominator n) $ \mpz_ptr2 -> + makeCF =<< (c_make_QQ_from_gmp mpz_ptr1 mpz_ptr2 0)++--------------------------------------------------------------------------------+-- * Base domain characteristic++foreign import ccall "get_characteristic" c_get_characteristic :: IO CInt+foreign import ccall "set_characteristic1" c_set_characteristic1 :: CInt -> IO ()+-- foreign import ccall "set_characteristic2" c_set_characteristic2 :: CInt -> CInt -> IO ()+foreign import ccall "set_characteristic3" c_set_characteristic3 :: CInt -> CInt -> CChar -> IO ()++getCharacteristic :: IO Int+getCharacteristic = fromIntegral <$> c_get_characteristic++-- | prime fields and QQ+setCharacteristic1 :: Int -> IO ()+setCharacteristic1 = c_set_characteristic1 . fromIntegral++{-+-- | prime power fields (meaning FF?)+-- apparently they removed this ????+setCharacteristic2 :: Int -> Int -> IO ()+setCharacteristic2 p n = c_set_characteristic2 (fromIntegral p) (fromIntegral n)+-}++-- | Galois fields+setCharacteristic3 :: Int -> Int -> Char -> IO ()+setCharacteristic3 p n ch = c_set_characteristic3 (fromIntegral p) (fromIntegral n) (castCharToCChar ch)++foreign import ccall "get_gf_value" c_get_gf_value :: Ptr CanonicalForm -> IO CInt+foreign import ccall "is_FF_in_GF" c_is_FF_in_GF :: Ptr CanonicalForm -> IO CInt+foreign import ccall "get_GF_degree" c_get_GF_degree :: IO CInt+foreign import ccall "get_GF_generator" c_get_GF_generator :: IO (Ptr CanonicalForm)++-- | This returns the exponent of the canonical generator.+-- If the input is zero, it appears to return the order of the field, q, but don't rely on this...+getGFValue :: CF -> IO Int+getGFValue cf = withForeignPtr cf $ \ptr -> fromIntegral <$> (c_get_gf_value ptr)++-- | True if element of the prime subfield+isFFinGF_IO :: CF -> IO Bool+isFFinGF_IO cf = withForeignPtr cf $ \ptr -> liftBool (c_is_FF_in_GF ptr)++-- | Returns the degree of the Galois field (degree of extension over the prime field)+getGFDegree :: IO Int+getGFDegree = fromIntegral <$> c_get_GF_degree++-- | Returns the generator of the Galois field+getGFGenerator :: IO CF+getGFGenerator = makeCF =<< c_get_GF_generator++--------------------------------------------------------------------------------+
+ src/Math/Singular/Factory/Internal/DList.hs view
@@ -0,0 +1,29 @@++-- | Difference lists, minimalistic edition++module Math.Singular.Factory.Internal.DList where++--------------------------------------------------------------------------------++import Data.List ( foldr )++--------------------------------------------------------------------------------++type DList a = [a] -> [a]++empty :: DList a+empty = id++singleton :: a -> DList a+singleton = (:)++toList :: DList a -> [a]+toList dl = dl []++append :: DList a -> DList a -> DList a+append = (.)++concat :: [DList a] -> DList a+concat = foldr append empty++--------------------------------------------------------------------------------
+ src/Math/Singular/Factory/Internal/Factory.hs view
@@ -0,0 +1,433 @@++-- | Medium-level bindings to singular-factory++{-# LANGUAGE BangPatterns, DataKinds, TypeSynonymInstances, FlexibleInstances #-}+module Math.Singular.Factory.Internal.Factory where++--------------------------------------------------------------------------------++import Data.List+import Data.Maybe+import Data.Ratio+import Data.Char+import Data.Word++import Control.Monad++import GHC.TypeLits+import Data.Proxy++import System.IO.Unsafe as Unsafe++import Numeric.GMP.Types+import qualified Numeric.GMP.Utils as GMP ++import Math.Singular.Factory.Internal.CanonicalForm+import Math.Singular.Factory.Internal.DList as DList++--------------------------------------------------------------------------------++-- | The maximum prime characteristic Factory can handle+-- (note: for prime power fields the limit is much smaller)+maxCharacteristic :: Int+maxCharacteristic = 536870909 -- 2^29-3++--------------------------------------------------------------------------------+-- * Version and configuration info++factoryVersion :: String+factoryVersion = Unsafe.unsafePerformIO getFactoryVersion++packageVersion :: String+packageVersion = Unsafe.unsafePerformIO getPackageVersion++haveFLINT, haveNTL, haveGMP :: Bool+haveFLINT = Unsafe.unsafePerformIO (cint2bool <$> c_have_FLINT)+haveNTL = Unsafe.unsafePerformIO (cint2bool <$> c_have_NTL )+haveGMP = Unsafe.unsafePerformIO (cint2bool <$> c_have_GMP )++--------------------------------------------------------------------------------+-- * Basic operations and instances++-- | Because the native equality comparison seems to be unreliable,+-- we provide an alternative implementation which subtracts the two+-- polynomials and then tests for the result being zero...+safeEqCF :: CF -> CF -> Bool+safeEqCF x y = isZeroCF (x - y)++-- | Note: this does not seem to be reliable in practice...+-- Better subtract them and then use isZeroCF...+nativeEqCF :: CF -> CF -> Bool+nativeEqCF x y = Unsafe.unsafePerformIO (isEqualIO x y)++{- there is already an instance... -}+-- instance Eq CF where (==) = eqCF++isZeroCF :: CF -> Bool+isZeroCF cf = Unsafe.unsafePerformIO (isZeroIO cf)++isOneCF :: CF -> Bool+isOneCF cf = Unsafe.unsafePerformIO (isOneIO cf)+ +varCF :: Var -> CF+varCF var = Unsafe.unsafePerformIO (varIO var)++varPowCF :: Var -> Int -> CF+varPowCF var expo = Unsafe.unsafePerformIO (varPowIO var expo)++instance Num CF where+ fromInteger n = Unsafe.unsafePerformIO $ newSmallConstCF $ fromIntegral n -- BIG INTS ARE NOT HANDLED!!!+ (+) x y = Unsafe.unsafePerformIO (plusIO x y)+ (-) x y = Unsafe.unsafePerformIO (minusIO x y)+ (*) x y = Unsafe.unsafePerformIO (timesIO x y)+ abs = error "CF: Num/abs is not implemented"+ signum = error "CF: Num/signum is not implemented"++powCF :: CF -> Int -> CF+powCF x n = Unsafe.unsafePerformIO (powIO x n)++modCF :: CF -> CF -> CF+modCF x y = Unsafe.unsafePerformIO (modIO x y)++divCF :: CF -> CF -> CF+divCF x y = Unsafe.unsafePerformIO (divIO x y)++substituteCF :: Var -> CF -> (CF -> CF)+substituteCF var what cf = Unsafe.unsafePerformIO (substituteIO var what cf)++gcdPolyCF :: CF -> CF -> CF+gcdPolyCF x y = Unsafe.unsafePerformIO (gcdPolyIO x y)++reduceCF :: CF -> CF -> CF+reduceCF x y = Unsafe.unsafePerformIO (reduceIO x y)++factorizeCF :: CF -> [(CF,Int)]+factorizeCF x = Unsafe.unsafePerformIO (factorizeIO x)++{-+-- | Factorization over prime fields. The flag is whether to perform substitution check+fpFactorizeCF :: CF -> Bool -> [(CF,Int)]+fpFactorizeCF x flag = Unsafe.unsafePerformIO (fpFactorizeIO x flag)++-- | Factorization over GF (prime power) fields. The flag is whether to perform substitution check+gfFactorizeCF :: CF -> Bool -> [(CF,Int)]+gfFactorizeCF x flag = Unsafe.unsafePerformIO (gfFactorizeIO x flag)++-- | Factorization over algebraic extensions of Q. The flag is whether to perform substitution check+ratFactorizeCF :: CF -> Var -> Bool -> [(CF,Int)]+ratFactorizeCF x alpha flag = Unsafe.unsafePerformIO (ratFactorizeIO x alpha flag)++-- | Factorization over algebraic extensions of a prime field. The flag is whether to perform substitution check+fqFactorizeCF :: CF -> Var -> Bool -> [(CF,Int)]+fqFactorizeCF x alpha flag = Unsafe.unsafePerformIO (fqFactorizeIO x alpha flag)+-}++--------------------------------------------------------------------------------+-- * pretty printing++showCF :: CF -> String+showCF x = Unsafe.unsafePerformIO (showIO x)++showCF_with :: (Int -> String) -> CF -> String+showCF_with showVar x = Unsafe.unsafePerformIO (showIO_with showVar x)++showCF_dense :: CF -> String+showCF_dense x = Unsafe.unsafePerformIO (showIO_dense x)++printCF :: CF -> IO ()+printCF cf = putStrLn =<< showIO cf++showIO :: CF -> IO String+showIO cf = do+ terms <- genericMarshalFromCF makeTerm cf+ return $ intercalate " + " (map prettyTerm terms)++showIO_with :: (Int -> String) -> CF -> IO String+showIO_with showVar cf = do+ terms <- genericMarshalFromCF makeTerm cf+ return $ intercalate " + " (map (prettyTermWith showVar) terms)++showIO_dense :: CF -> IO String+showIO_dense cf = do+ terms <- genericMarshalFromCF makeTerm cf+ return $ intercalate "+" (map prettyTerm terms)++--------------------------------------------------------------------------------+-- * Galois fields++-- | Values in a Galois field.+--+-- They can either 0, or a power of the canonical generator (of the multiplicative+-- group, which is cyclic).+-- +-- Furthermore, they can be possibly also element of the prime subfield.+--+data GFValue+ = GFZero+ | GFSubField { _gfGenExpo :: !Int , _gfModP :: !Int } + | GFGenPow { _gfGenExpo :: !Int }+ deriving (Eq,Ord)++instance Show GFValue where+ show = showGFValue1 "#"++-- | Elements of the prime subfield are shown as numbers, the rest as+-- powers of the generator+showGFValue1 :: String -> GFValue -> String+showGFValue1 gen gfv = case gfv of+ GFZero -> "0"+ GFSubField expo modp -> show modp+ GFGenPow expo -> if expo == 1 then gen else gen ++ "^" ++ show expo++-- | Elements of the prime subfield are also shown as powers of the generator+showGFValue2 :: String -> GFValue -> String+showGFValue2 gen gfv = case gfv of+ GFZero -> "0"+ GFSubField expo modp -> if expo == 1 then gen else gen ++ "^" ++ show expo+ GFGenPow expo -> if expo == 1 then gen else gen ++ "^" ++ show expo++--------------------------------------------------------------------------------+-- * Base domains+ +data BaseValue+ = ZZ !Integer+ | QQ !Rational+ | FF !Int+ | GF !GFValue+ deriving (Eq,Ord,Show)++baseValueIsOne :: BaseValue -> Bool+baseValueIsOne val = case val of+ ZZ n -> n == 1+ QQ q -> q == 1+ GF gfv -> case gfv of { GFSubField _ 1 -> True ; _ -> False }+ FF k -> k == 1++prettyBaseValue :: BaseValue -> String+prettyBaseValue val = case val of+ ZZ n -> show n+ QQ q -> case denominator q of+ 1 -> show (numerator q)+ b -> show (numerator q) ++ "/" ++ show b+ GF k -> show k -- "<" ++ show k ++ ">"+ FF k -> show k -- "<" ++ show k ++ ">"++--------------------------------------------------------------------------------+-- * Monomials++type Level = Int+type Expo = Int++newtype Monom + = Monom [(Level,Expo)] + deriving (Eq,Ord,Show)++monomIsNull :: Monom -> Bool+monomIsNull (Monom list) = null list++prettyMonom :: Monom -> String+prettyMonom = prettyMonomWith g where+ g level = [chr (96 + level)]++prettyMonomWith :: (Int -> String) -> Monom -> String+prettyMonomWith showVar (Monom [] ) = "1" -- "(1)"+prettyMonomWith showVar (Monom ves) = intercalate "*" (map f ves) where+ f (v,0) = "1"+ f (v,1) = showVar v+ f (v,k) = showVar v ++ "^" ++ show k ++----------------------------------------+-- * coefficients++type Coeff = BaseValue -- TEMPORARY HACK++coeffIsOne :: Coeff -> Bool+coeffIsOne = baseValueIsOne++prettyCoeff = prettyBaseValue++----------------------------------------+-- * Terms++data Term + = Term !Coeff !Monom+ deriving (Eq,Ord,Show)++prettyTerm :: Term -> String+prettyTerm (Term coeff monom) + | coeffIsOne coeff = prettyMonom monom+ | monomIsNull monom = prettyCoeff coeff+ | otherwise = prettyCoeff coeff ++ "*" ++ prettyMonom monom++prettyTermWith :: (Int -> String) -> Term -> String+prettyTermWith showVar (Term coeff monom) + | coeffIsOne coeff = prettyMonomWith showVar monom+ | monomIsNull monom = prettyCoeff coeff+ | otherwise = prettyCoeff coeff ++ "*" ++ prettyMonomWith showVar monom++--------------------------------------------------------------------------------+-- * Marshalling from CF++getZZ :: CF -> IO (Maybe Integer)+getZZ cf = isInZZ_IO cf >>= \b -> case b of+ False -> return Nothing+ True -> isImmediateIO cf >>= \b -> case b of+ True -> (Just . fromIntegral) <$> getSmallIntValue cf+ False -> Just <$> getGmpNumerator cf+ -- error "getZZ: bignums are not implemented yet"++getQQ :: CF -> IO (Maybe Rational)+getQQ cf = isInQQ_IO cf >>= \b -> case b of+ False -> return Nothing+ True -> do+ -- Just numer <- (getZZ =<< getNumer cf)+ -- Just denom <- (getZZ =<< getDenom cf)+ numer <- getGmpNumerator cf+ denom <- getGmpDenominator cf+ return $ Just $ (numer % denom)++getFF :: CF -> IO (Maybe Int)+getFF cf = isInFF_IO cf >>= \b -> case b of+ False -> return Nothing+ True -> isImmediateIO cf >>= \b -> case b of+ True -> (Just . fromIntegral) <$> getSmallIntValue cf+ False -> error "getFF: bignums are not implemented yet"++getGF :: CF -> IO (Maybe GFValue)+getGF cf = isInGF_IO cf >>= \b -> case b of+ False -> return Nothing+ True -> isFFinGF_IO cf >>= \b -> case b of+ True -> do + k <- getSmallIntValue cf + e <- getGFValue cf+ return $ Just $ if (k==0) then GFZero else (GFSubField e k)+ False -> do+ e <- getGFValue cf+ return $ Just $ GFGenPow e+ +getBaseValue :: CF -> IO (Maybe BaseValue)+getBaseValue cf = isInBaseDomainIO cf >>= \b -> case b of+ False -> return Nothing+ True -> getBaseValueNotGF cf >>= \mb -> case mb of+ Just val -> return $ Just val+ Nothing -> getGF cf >>= \mb -> case mb of+ Just gf -> return $ Just (GF gf)+ Nothing -> return Nothing++getBaseValueNotGF :: CF -> IO (Maybe BaseValue)+getBaseValueNotGF cf = isInBaseDomainIO cf >>= \b -> case b of+ False -> return Nothing+ True -> getZZ cf >>= \mb -> case mb of+ Just n -> return $ Just (ZZ n)+ Nothing -> getQQ cf >>= \mb -> case mb of+ Just q -> return $ Just (QQ q)+ Nothing -> getFF cf >>= \mb -> case mb of+ Just k -> return $ Just (FF k)+ Nothing -> return Nothing+ +--------------------------------------------------------------------------------++isInBaseDomainCF :: CF -> Bool+isInBaseDomainCF cf = Unsafe.unsafePerformIO (isInBaseDomainIO cf)++isInCoeffDomainCF :: CF -> Bool+isInCoeffDomainCF cf = Unsafe.unsafePerformIO (isInCoeffDomainIO cf)++isInPolyDomainCF :: CF -> Bool+isInPolyDomainCF cf = Unsafe.unsafePerformIO (isInPolyDomainIO cf)++isInQuotDomainCF :: CF -> Bool+isInQuotDomainCF cf = Unsafe.unsafePerformIO (isInQuotDomainIO cf)++isInExtensionCF :: CF -> Bool+isInExtensionCF cf = Unsafe.unsafePerformIO (isInExtensionIO cf)++--------------------------------------------------------------------------------++valueZZ :: CF -> Integer+valueZZ cf = case Unsafe.unsafePerformIO (getZZ cf) of+ Just n -> n+ Nothing -> error "valueZZ: not an integer"++valueQQ :: CF -> Rational+valueQQ cf = case Unsafe.unsafePerformIO (getQQ cf) of+ Just n -> n+ Nothing -> error "valueQQ: not a rational"++valueGF :: CF -> GFValue+valueGF cf = case Unsafe.unsafePerformIO (getGF cf) of+ Just n -> n+ Nothing -> error "valueGF: not a GF element"++valueFF :: CF -> Int+valueFF cf = case Unsafe.unsafePerformIO (getFF cf) of+ Just n -> n+ Nothing -> error "valueFF: not a FF element"++--------------------------------------------------------------------------------++makeMonom :: [(Level,Expo)] -> Monom+makeMonom ves = Monom $ filter cond ves where cond (lev,expo) = expo > 0++makeTerm :: [(Level,Expo)] -> BaseValue -> Term+makeTerm ves cf = Term cf (makeMonom ves)++genericMarshalFromCF :: ([(Level,Expo)] -> BaseValue -> a) -> CF -> IO [a]+genericMarshalFromCF user cf = DList.toList <$> (genericMarshalFromCF_dlist user cf)++--------------------------------------------------------------------------------++genericMarshalFromCF_dlist :: ([(Level,Expo)] -> BaseValue -> a) -> CF -> IO (DList a)+genericMarshalFromCF_dlist user = worker [] where+ worker expos cf = do+ getBaseValue cf >>= \mb -> case mb of+ Just val -> return (DList.singleton $ user expos val)+ Nothing -> do+ level <- getLevel cf+ deg <- getDegree cf+ stuff <- forM [0..deg] $ \d -> do+ this <- getCfAtIndex cf d+ isZeroIO this >>= \b -> if b+ then return (DList.empty)+ else if d > 0 + then worker ((level,d):expos) this+ else worker expos this+ return $ DList.concat stuff++{-+genericMarshalFromCF_list :: ([(Level,Expo)] -> BaseValue -> a) -> CF -> IO [a]+genericMarshalFromCF_list user = worker [] where+ worker expos cf = do+ getBaseValue cf >>= \mb -> case mb of+ Just val -> return [user expos val]+ Nothing -> do+ level <- getLevel cf+ deg <- getDegree cf+ stuff <- forM [0..deg] $ \d -> do+ this <- getCfAtIndex cf d+ isZero this >>= \b -> if b+ then return []+ else if d > 0 + then worker ((level,d):expos) this+ else worker expos this+ return $ Data.List.concat stuff+-}++--------------------------------------------------------------------------------++marshalUnivariateFromCF :: CF -> IO [(CF,Int)]+marshalUnivariateFromCF = worker where+ worker cf = do+ deg <- getDegree cf+ case deg of+ 0 -> return [(cf,0)]+ _ -> do+ -- level <- getLevel cf+ mbs <- forM [0..deg] $ \d -> do+ this <- getCfAtIndex cf d+ isZeroIO this >>= \b -> if b+ then return $ Nothing+ else return $ Just (this,d)+ return $ catMaybes mbs+ +--------------------------------------------------------------------------------
+ src/Math/Singular/Factory/Parser.hs view
@@ -0,0 +1,326 @@++-- | Parsing polynomials and polynomial expressions++{-# LANGUAGE BangPatterns #-}+module Math.Singular.Factory.Parser + ( -- * Parsing polynomials + parseExpr , parseGenPoly+ , parseStringExpr , parseStringGenPoly+ -- * Parser monad+ , Parser, runParser+ , (<||>) , try+ , many , many1+ -- * Parsers+ , charP , charP_ , charsP+ , spacesP_ , eofP + , signP , natP , integerP , identifierP+ , exprP , genPolyP+ ) + where++--------------------------------------------------------------------------------++import Data.Char+import Data.List++import Control.Applicative+import Control.Monad++import Data.Traversable++import Data.Proxy++import Data.Text.Lazy ( Text )+import qualified Data.Text.Lazy as T+import qualified Data.Text.Lazy.Read as T++import Math.Singular.Factory.Expr+import Math.Singular.Factory.Variables++import Math.Singular.Factory.Internal.DList as DList++--------------------------------------------------------------------------------++type Var = String++--------------------------------------------------------------------------------+-- * the Parser monad++newtype Parser a = P { runParser :: Text -> Either String (a,Text) }++instance Functor Parser where+ fmap f (P action) = P $ \text -> case action text of+ Right (x, rest) -> Right (f x, rest)+ Left msg -> Left msg++instance Applicative Parser where+ pure = return+ (<*>) = ap++instance Monad Parser where+ return x = P $ \text -> Right (x,text)+ (P action) >>= u = P $ \text -> case action text of+ Right (x, rest) -> runParser (u x) rest+ Left msg -> Left msg++--------------------------------------------------------------------------------++try :: Parser a -> Parser (Maybe a)+try p = P $ \text -> case runParser p text of+ Right (x, rest) -> Right (Just x , rest)+ Left msg -> Right (Nothing, text)++infixr 5 <||>++(<||>) :: Parser a -> Parser a -> Parser a+(<||>) p q = do+ mb <- try p+ case mb of+ Just y -> return y+ Nothing -> q++instance Alternative Parser where + (<|>) = (<||>)+ +many1 :: Parser a -> Parser [a]+many1 p = do+ x <- p+ xs <- many p+ return (x:xs)++--------------------------------------------------------------------------------+ +charP_ :: (Char -> Bool) -> Parser ()+charP_ cond = void $ charP cond++charP :: (Char -> Bool) -> Parser Char+charP cond = P $ \text -> case T.uncons text of+ Nothing -> Left "unexpected end of input"+ Just (ch,rest) -> if cond ch+ then Right (ch , rest)+ else Left "unexpected character"++charsP :: (Char -> Bool) -> Parser [Char]+charsP cond = P $ \text -> case T.span cond text of+ (this,rest) -> Right (T.unpack this, rest)++eofP :: Parser ()+eofP = P $ \text -> if T.null text then Right ((),text) else Left "expected the end of input"++spacesP_ :: Parser ()+spacesP_ = P $ \text -> case T.span isSpace text of + (_,rest) -> Right ((),rest) ++withEof :: Parser a -> Parser a +withEof action = do+ y <- action+ spacesP_+ eofP+ return y++withSpaces :: Parser a -> Parser a +withSpaces action = do+ y <- action+ spacesP_+ return y++--------------------------------------------------------------------------------+-- * Parsing simple things++_signP :: Parser Sign+_signP = charP (\c -> (c=='+' || c=='-')) >>= \ch -> return $ if (ch=='+') then Plus else Minus++signP :: Parser Sign+signP = withSpaces _signP++optionalSignP :: Parser Sign+optionalSignP = do+ mb <- try signP+ return $ case mb of+ Just pm -> pm+ Nothing -> Plus++inParensP :: Parser a -> Parser a+inParensP action = do+ charP_ (=='(')+ spacesP_+ y <- withSpaces action+ charP_ (==')')+ spacesP_+ return y++natP :: Parser Int+natP = P (T.decimal)++naturalP :: Parser Integer+naturalP = P (T.decimal)++integerP :: Parser Integer+integerP = P (T.signed T.decimal)++identifierP :: Parser String+identifierP = do+ x <- charP isAlpha+ xs <- charsP $ \c -> isAlpha c || isDigit c || (c == '_')+ return (x:xs)++--------------------------------------------------------------------------------+-- * parsing polynomials++varP :: Parser Var+varP = withSpaces identifierP++kstP :: Parser Integer+kstP = withSpaces integerP++varPowP :: Parser (Var,Int)+varPowP = do+ v <- varP+ mb <- try $ do+ charP_ (=='^')+ spacesP_+ expo <- natP+ spacesP_+ return expo+ case mb of+ Nothing -> return (v,1)+ Just e -> return (v,e)++_monomP :: Parser [(Var,Int)]+_monomP = do+ ve <- varPowP+ mb <- try $ do+ charP_ (=='*')+ spacesP_+ ves <- _monomP+ return ves+ case mb of+ Nothing -> return (ve:[] )+ Just ves -> return (ve:ves)++monomP :: Parser (Monom Var)+monomP = Monom <$> _monomP+ +_termP :: Parser (Integer, Monom Var)+_termP = do+ pm <- withSpaces optionalSignP+ mbcf <- try (withSpaces integerP)+ void $ try $ withSpaces (charP_ (=='*'))+ monom <- case mbcf of+ Nothing -> monomP+ Just _ -> maybe (Monom []) id <$> try monomP+ let cf = maybe 1 id mbcf+ return (negateIfMinus pm cf , monom)+ +termP :: Parser (Term Integer Var)+termP = (uncurry Term) <$> _termP++genPolyP :: Parser (GenPoly Integer Var)+genPolyP = (GenPoly . filter isNotZero) <$> (spacesP_ >> many1 termP) where+ isNotZero (Term cf _) = cf /= 0+ +--------------------------------------------------------------------------------+-- * Parsing polynomial expressions++exprP :: Parser (Expr Var)+exprP = do+ spacesP_ + level3++atomicP = (VarE <$> varP) <||> (KstE <$> kstP) <||> inParensP exprP++level0 = atomicP+level1 = powP <||> atomicP +level2 = productP <||> powP <||> atomicP +level3 = sumP <||> productP <||> powP <||> atomicP ++powP :: Parser (Expr Var)+powP = do+ (e,n) <- _powP+ return $ case n of+ 0 -> KstE 1+ 1 -> e+ _ -> PowE e n++_powP :: Parser (Expr Var,Int)+_powP = do+ e <- level0+ spacesP_+ charP_ (=='^')+ spacesP_+ n <- natP+ spacesP_+ return (e,n)++productP :: Parser (Expr Var)+productP = do+ es <- _productP+ return $ case es of+ [x] -> x+ _ -> MulE es++_productP :: Parser [Expr Var]+_productP = do+ e1 <- level1+ spacesP_+ mb <- try $ do+ charP_ (=='*')+ spacesP_+ es <- _productP+ return es+ case mb of+ Nothing -> return (e1:[])+ Just es -> return (e1:es)++sumP :: Parser (Expr Var)+sumP = do+ es <- _sumP+ return $ case es of+ [(Plus ,x)] -> x+ [(Minus,x)] -> NegE x+ _ -> LinE es++_sumP :: Parser [(Sign,Expr Var)]+_sumP = do+ pm <- optionalSignP+ (this,rest) <- __sumP+ return ((pm,this):rest)++__sumP :: Parser ( Expr Var , [(Sign,Expr Var)] )+__sumP = do+ e1 <- level2+ spacesP_+ mb <- try $ do+ pm <- signP+ spacesP_+ (e,lin) <- __sumP+ return ((pm,e):lin)+ case mb of+ Nothing -> return (e1,[] )+ Just lin -> return (e1,lin)++--------------------------------------------------------------------------------++parseStringExpr :: Text -> Either String (Expr Var)+parseStringExpr text = case runParser (withEof exprP) text of+ Right (y,_) -> Right y+ Left msg -> Left msg++parseStringGenPoly :: Text -> Either String (GenPoly Integer Var)+parseStringGenPoly text = case runParser (withEof genPolyP) text of+ Right (y,_) -> Right y+ Left msg -> Left msg++--------------------------------------------------------------------------------++parseGenPoly :: forall vars. VariableSet vars => Proxy vars -> Text -> Maybe (GenPoly Integer VarIdx)+parseGenPoly pxy text = case parseStringGenPoly text of+ Left {} -> Nothing+ Right gp -> sequence $ fmap (recogVarName pxy) gp ++parseExpr :: forall vars. VariableSet vars => Proxy vars -> Text -> Maybe (Expr VarIdx)+parseExpr pxy text = case parseStringExpr text of+ Left {} -> Nothing+ Right e -> sequence $ fmap (recogVarName pxy) e + +--------------------------------------------------------------------------------
+ src/Math/Singular/Factory/Polynomial.hs view
@@ -0,0 +1,158 @@++-- | High-level bindings to singular-factory++{-# LANGUAGE + BangPatterns, PatternSynonyms, KindSignatures, DataKinds,+ FlexibleInstances, TypeSynonymInstances, ScopedTypeVariables,+ EmptyDataDecls+ #-}+module Math.Singular.Factory.Polynomial where++--------------------------------------------------------------------------------++import GHC.TypeLits+import Data.Proxy++import Data.Text.Lazy ( Text , pack )++import System.IO.Unsafe as Unsafe++import Math.Singular.Factory.Internal.CanonicalForm+import Math.Singular.Factory.Internal.Factory++import Math.Singular.Factory.Variables+import Math.Singular.Factory.Domains++import Math.Singular.Factory.Expr+import Math.Singular.Factory.Parser++--------------------------------------------------------------------------------+-- * Polynomials++-- | A multivariate polynomial over a base domain.+--+-- Typically, you want to fix your variable set (see the module "Math.Singular.Factory.Variables"), +-- make a type synonym, and use that; for example:+--+-- > type Poly domain = Polynomial (VarN "x") domain+--+newtype Polynomial varset domain + = Poly { unPoly :: CF }++instance Eq (Polynomial vars domain) where+ (==) (Poly cf1) (Poly cf2) = safeEqCF cf1 cf2++instance forall vars domain. VariableSet vars => Show (Polynomial vars domain) where+ show (Poly cf) = showCF_with (varIdxName (Proxy :: Proxy vars)) cf+ +polyIsZero :: Polynomial vars domain -> Bool+polyIsZero (Poly cf) = isZeroCF cf++polyIsOne :: Polynomial vars domain -> Bool+polyIsOne (Poly cf) = isOneCF cf++-- | Returns true if the polynomial is a constant +inBaseDomain :: Polynomial vars domain -> Bool+inBaseDomain (Poly cf) = isInBaseDomainCF cf++-- | If it is a constant, returns the value+mbConstant :: BaseDomain domain => Polynomial vars domain -> Maybe domain+mbConstant (Poly cf) = if isInBaseDomainCF cf + then Just (unsafeCfToBase cf)+ else Nothing++-- | A constant polynomial+konst :: BaseDomain domain => domain -> Polynomial vars domain+konst = Poly . baseToCF++-- | A variable as a polynomial+var :: VarIdx -> Polynomial vars domain+var idx = Poly $ varCF (theNthVar idx)++-- | A power of a variable+varPow :: VarIdx -> Int -> Polynomial vars domain+varPow idx expo = Poly $ varPowCF (theNthVar idx) expo ++--------------------------------------------------------------------------------+-- * Operations on polynomials++mapIntoDomain + :: forall domain1 domain2 vars. (BaseDomain domain1, BaseDomain domain2) + => Polynomial vars domain1 -> Polynomial vars domain2+mapIntoDomain (Poly cf) = result where+ result = Poly (mapIntoCF (factoryChar pxy) cf)+ pxy = Proxy :: Proxy domain2++instance forall vars domain. BaseDomain domain => Num (Polynomial vars domain) where+ fromInteger = Poly . (baseToCF :: domain -> CF) . fromInteger+ negate (Poly cf) = Poly (negate cf)+ (Poly cf1) + (Poly cf2) = Poly (cf1 + cf2)+ (Poly cf1) - (Poly cf2) = Poly (cf1 - cf2)+ (Poly cf1) * (Poly cf2) = Poly (cf1 * cf2)+ abs = id+ signum = const 1+ +pow :: BaseDomain domain => Polynomial vars domain -> Int -> Polynomial vars domain+pow (Poly cf) expo = Poly $ powCF cf expo++-- | Polynomial GCD+polyGCD :: BaseDomain domain => Polynomial vars domain -> Polynomial vars domain -> Polynomial vars domain +polyGCD (Poly cf1) (Poly cf2) = Poly $ gcdPolyCF cf1 cf2++-- | Polynomial reduction+polyReduce :: BaseDomain domain => Polynomial vars domain -> Polynomial vars domain -> Polynomial vars domain +polyReduce (Poly cf1) (Poly cf2) = Poly $ reduceCF cf1 cf2++-- | Polynomial factorization +factorize :: BaseDomain domain => Polynomial vars domain -> [(Polynomial vars domain, Int)]+factorize (Poly cf) = map f (factorizeCF cf) where+ f (p, expo) = (Poly p, expo)++{-+-- | Polynomial factorization (the new algorithms by Martin Lee)+factorizeNew :: forall vars domain. BaseDomain domain => Polynomial vars domain -> [(Polynomial vars domain, Int)]+factorizeNew (Poly cf) = + case factoryChar (Proxy :: Proxy domain) of+ CharZero -> map f (ratFactorizeCF cf alphaOne True)+ CharFp p -> map f (fpFactorizeCF cf True)+ CharGF p n -> map f (gfFactorizeCF cf True)+ where+ f (p, expo) = (Poly p, expo)+ alphaOne = theNthVar 1 -- const Variable& v= Variable (1) + +-- | Polynomial factorization (old way)+factorizeOld :: BaseDomain domain => Polynomial vars domain -> [(Polynomial vars domain, Int)]+factorizeOld (Poly cf) = map f (oldFactorizeCF cf) where+ f (p, expo) = (Poly p, expo)+-}++-- | Substitution+substitute1 :: BaseDomain domain => VarIdx -> Polynomial vars domain -> Polynomial vars domain -> Polynomial vars domain+substitute1 idx (Poly what) (Poly cf) = Poly (substituteCF (theNthVar idx) what cf)++-- | Evaluate a polynomial at the given point+evaluate :: BaseDomain domain => (VarIdx -> domain) -> Polynomial vars domain -> domain+evaluate fun (Poly cf0) = unsafeCfToBase (go 1 cf0) where+ go :: Int -> CF -> CF+ go !idx !cf = if isInBaseDomainCF cf+ then cf+ else go (idx+1) (substituteCF (theNthVar idx) (baseToCF $ fun idx) cf)++--------------------------------------------------------------------------------+-- * Parsing++-- | Parse a polynomial in expanded form+parsePolynomial :: forall vars. VariableSet vars => Text -> Maybe (Polynomial vars Integer)+parsePolynomial text = evalGenPoly konst var <$> parseGenPoly (Proxy :: Proxy vars) text++-- | Parse a polynomial expression (for example the product of two polynomials)+parsePolyExpr :: forall vars. VariableSet vars => Text -> Maybe (Polynomial vars Integer)+parsePolyExpr text = evalExpr {- konst -} var <$> parseExpr (Proxy :: Proxy vars) text++parsePolynomialStr :: forall vars. VariableSet vars => String -> Maybe (Polynomial vars Integer)+parsePolynomialStr = parsePolynomial . pack++parsePolyExprStr :: forall vars. VariableSet vars => String -> Maybe (Polynomial vars Integer)+parsePolyExprStr = parsePolyExpr . pack++--------------------------------------------------------------------------------
+ src/Math/Singular/Factory/Variables.hs view
@@ -0,0 +1,208 @@++-- | Variables.+--+-- Singular-factory supports only a single linear sequence of variables,+-- indexed starting from 1, optionally having single-character names.+--+-- So what we do is to use (phantom) types to encode naming conventions.+--++{-# LANGUAGE BangPatterns, DataKinds, ScopedTypeVariables, KindSignatures #-}+module Math.Singular.Factory.Variables where++--------------------------------------------------------------------------------++import Data.Char+import Data.List ( findIndex )+import Text.Read++import Data.Proxy+import GHC.TypeLits++import System.IO.Unsafe as Unsafe++import Math.Singular.Factory.Internal.CanonicalForm -- Factory++--------------------------------------------------------------------------------+-- * Raw factory variables++-- | A variable index. +--+-- In factory, there is a single linear sequence of variables.+-- Variables are indexed starting from 1.+-- +type VarIdx = Int++-- | In factory, there is a single linear sequence of variables.+-- We \"precalculate\" these (lazily).+theFactoryVars :: [Var]+theFactoryVars = map mk [1..] where+ mk i = Unsafe.unsafePerformIO $ newVarL i++theNthVar :: VarIdx -> Var+theNthVar idx = theFactoryVars !! (idx-1)++--------------------------------------------------------------------------------+-- * Variable sets ++-- | The class of variable sets. Since Factory only supports a single linear+-- variable set, these differ only by naming conventions.+--+class VariableSet v where+ varIdxName :: Proxy v -> VarIdx -> String+ recogVarName :: Proxy v -> String -> Maybe VarIdx++-- | The variable set @x1, x2, x3, x4...@ (where \"x\" can be any string)+data VarN (s :: Symbol) ++-- | The variable set @x_1, x_2, x_3, x_4...@ (where \"x\" can be any string)+data Var_N (s :: Symbol) ++-- | The variable set @x[1], x[2], x[3], x[4]...@ (where \"x\" can be any string)+data VarBracketN (s :: Symbol) ++-- | The variable set @a, b, c, d...@+data VarAbc ++-- | The variable set @A, B, C, D...@+data VarABC ++-- | The variable set @x, y, z, u, v, w, a, b, c...@+data VarXyz ++-- | The variable set @X, Y, Z, U, V, W, A, B, C...@+data VarXYZ ++instance forall s. KnownSymbol s => VariableSet (VarN s) where+ varIdxName _ = indexedVars (symbolVal (Proxy :: Proxy s))+ recogVarName _ = recogIndexed (symbolVal (Proxy :: Proxy s))++instance forall s. KnownSymbol s => VariableSet (Var_N s) where+ varIdxName _ = indexedVarsUnderscore (symbolVal (Proxy :: Proxy s))+ recogVarName _ = recogIndexedUnderscore (symbolVal (Proxy :: Proxy s))++instance forall s. KnownSymbol s => VariableSet (VarBracketN s) where+ varIdxName _ = indexedVarsBracket (symbolVal (Proxy :: Proxy s))+ recogVarName _ = recogIndexedBracket (symbolVal (Proxy :: Proxy s))++instance VariableSet VarAbc where+ varIdxName _ = abcVars+ recogVarName _ = recogAbc ++instance VariableSet VarABC where+ varIdxName _ = capitalAbcVars+ recogVarName _ = recogABC++instance VariableSet VarXyz where+ varIdxName _ = xyzVars+ recogVarName _ = recogXyz+ +instance VariableSet VarXYZ where+ varIdxName _ = capitalXyzVars+ recogVarName _ = recogXYZ+ +--------------------------------------------------------------------------------+-- * Standard naming conventions of variables++-- | Eg. @x1, x2, x3...@+indexedVars :: String -> VarIdx -> String+indexedVars prefix = \i -> prefix ++ show i++-- | Eg. @x_1, x_2, x_3...@+indexedVarsUnderscore :: String -> VarIdx -> String+indexedVarsUnderscore prefix = \i -> prefix ++ "_" ++ show i++-- | Eg. @x[1], x[2], x[3]...@+indexedVarsBracket :: String -> VarIdx -> String+indexedVarsBracket prefix = \i -> prefix ++ "[" ++ show i ++ "]"++-- | That is, @a, b, c...@+abcVars :: VarIdx -> String+abcVars idx = lowerVarList !! (idx-1)++-- | That is, @A, B, C...@+capitalAbcVars :: VarIdx -> String+capitalAbcVars idx = lowerVarList !! (idx-1)++-- | @x, y, z, u, v, w, a, b, c ... , t@+xyzVars :: VarIdx -> String+xyzVars idx = [ varListXyz !! (idx-1) ]++capitalXyzVars :: VarIdx -> String+capitalXyzVars idx = [ varListCapitalXYZ !! (idx-1) ]++--------------------------------------------------------------------------------+-- * Variable lists++varListXyz :: [Char]+varListXyz = "xyzuvwabcdefghijklmnopqrst" ++varListCapitalXYZ :: [Char]+varListCapitalXYZ = "XYZUVWABCDEFGHIJKLMNOPQRST"++-- | The infinite list of variables @a, b ..., z, aa, ab, ac, ...@+lowerVarList :: [String]+lowerVarList = map (:[]) abc ++ [ ys ++ [y] | ys<-lowerVarList , y<-abc ] where+ abc = ['a'..'z']++upperVarList :: [String]+upperVarList = map (:[]) abc ++ [ ys ++ [y] | ys<-lowerVarList , y<-abc ] where+ abc = ['A'..'Z']++--------------------------------------------------------------------------------+-- * Parsing standard variable names++readPosIdxMaybe :: String -> Maybe VarIdx+readPosIdxMaybe s = case readMaybe s :: Maybe Word of+ Nothing -> Nothing+ Just w -> let j = (fromIntegral w :: Int) + in if j >= 1 then Just j else Nothing+ +recogIndexed :: String -> String -> Maybe VarIdx+recogIndexed !prefix = recog where+ !n = length prefix+ recog s = case splitAt n s of + (p,q) -> if p /= prefix+ then Nothing+ else readPosIdxMaybe q + +recogIndexedUnderscore :: String -> String -> Maybe VarIdx+recogIndexedUnderscore !prefix = recog where+ !n = length prefix+ recog s = case splitAt n s of + (p,q) -> if p /= prefix+ then Nothing+ else case q of+ ('_':r ) -> readPosIdxMaybe r+ _ -> Nothing+ +recogIndexedBracket :: String -> String -> Maybe VarIdx+recogIndexedBracket !prefix = recog where+ !n = length prefix+ recog s = case splitAt n s of + (p,q) -> if p /= prefix+ then Nothing+ else if length q >= 3 && head q == '[' && last q == ']'+ then readPosIdxMaybe (init $ tail q) + else Nothing+ +recogAbc :: String -> Maybe VarIdx+recogAbc [c] = if c >= 'a' && c <= 'z' then Just (ord c - 96) else Nothing+recogAbc [] = Nothing+recogAbc _ = Nothing ++recogABC :: String -> Maybe VarIdx+recogABC [c] = if c >= 'A' && c <= 'Z' then Just (ord c - 64) else Nothing+recogABC [] = Nothing+recogABC _ = Nothing ++recogXyz :: String -> Maybe VarIdx+recogXyz [c] = if c >= 'a' && c <= 'z' then (+1) <$> findIndex (==c) varListXyz else Nothing+recogXyz _ = Nothing ++recogXYZ :: String -> Maybe VarIdx+recogXYZ [c] = if c >= 'A' && c <= 'Z' then (+1) <$> findIndex (==c) varListCapitalXYZ else Nothing+recogXYZ _ = Nothing ++--------------------------------------------------------------------------------+
+ test/TestSuite.hs view
@@ -0,0 +1,256 @@++-- | The test-suite++{-# LANGUAGE BangPatterns, DataKinds, DeriveFunctor #-}+module Main where++--------------------------------------------------------------------------------++import Data.List++import Control.Monad+import System.Random++import Test.Tasty+import Test.Tasty.HUnit++import Math.Singular.Factory++import Math.Singular.Factory.Domains+import Math.Singular.Factory.Polynomial+import Math.Singular.Factory.Counting+import Math.Singular.Factory.Variables++--------------------------------------------------------------------------------++main = do+ initialize+ printConfig+ defaultMain tests++tests :: TestTree+tests = testGroup "Tests" + [ unit_tests+-- , randomized_tests+ ]++unit_tests :: TestTree+unit_tests = testGroup "Unit tests"+ [ testCase "reconstruction for some polys over Z" (assertBool "failed" $ reconstr_some_polys some_polys_ZZ)+ , testGroup "reconstr. of some more polys over Z" + [ testCase ("poly #" ++ show i) (assertBool "failed" $ prop_reconstr_from_factors p) + | (i,p) <- zip [0..] some_more_polys_ZZ + ]+ , testCase "reconstruction for some polys over F_2" (assertBool "failed" $ reconstr_some_polys some_polys_F2)+ , testCase "reconstruction for some polys over F_3" (assertBool "failed" $ reconstr_some_polys some_polys_F3)+ , testCase "reconstruction for some polys over F_5" (assertBool "failed" $ reconstr_some_polys some_polys_F5)+ , testCase "reconstruction for some polys over GF(4)" (assertBool "failed" $ reconstr_some_polys some_polys_GF4)+ , testCase "reconstruction for some polys over GF(8)" (assertBool "failed" $ reconstr_some_polys some_polys_GF8)+ , testCase "reconstruction for some polys over GF(9)" (assertBool "failed" $ reconstr_some_polys some_polys_GF9)+ ] + +--------------------------------------------------------------------------------++type Poly domain = Polynomial VarAbc domain ++some_polys_ZZ :: [Poly Integer]+some_polys_ZZ = + [ (x^2 + 1) * (x^5 + 1) * (x^7 + 1)+ + , x^2 - y^2+ , y^2 - z^2+ , x^5 - y^5+ , x^7 - y^7+ , x^10 - y^10+ + , (1 + x + y + z)^2+ , (1 + x + y + z)^4+ , (1 + x + y + z)^8+ + , (1 + x + y + z)^2 - 1+ , (1 + x + y + z)^4 - 1+ , (1 + x + y + z)^8 - 1+ + , (1 + x^2 + y^2 + z^2)^2 - 1+ , (1 + x^2 + y^2 + z^2)^4 - 1+ , (1 + x^2 + y^2 + z^2)^8 - 1 ++ , ((1 - x - y - z)^2 - 1) * ((1 - x - y - z )^2 + 1) + , ((1 + x + y + z)^2 - 1) * ((1 - x - y - z )^2 + 1) + , ((1 + x + y + z)^2 - 1) * ((1 + x + y + z )^2 + 1) + ] + where+ myvars@[x,y,z,u,v,w] = map var [1..6]++-- | These seem to be too big for finite fields except GF(2) ???+some_more_polys_ZZ :: [Poly Integer]+some_more_polys_ZZ=+ [ (x-13) * (x+27) * (x-42)^2 * (x+7)^3 * (x-11)^5+ , ( (1+x+y+z)^4 + 1 ) * ( (1+x+y+z)^4 + 2 ) + , ( (1+x+y+z)^5 + 1 ) * ( (1+x+y+z)^5 + 2 ) + , ( (1+x+y+z)^7 + 1 ) * ( (1+x+y+z)^7 + 2 ) + , ( (1+x+y+z)^10 + 1 ) * ( (1+x+y+z)^10 + 2 ) + , ( (1+x+y+z)^20 + 1 ) * ( (1+x+y+z)^20 + 2 ) + ] +++ [ sparse1 hk | hk <- [5,8..25] ] +++ [ sparse2 k | k <- [5..15] ] + where+ myvars@[x,y,z,u,v,w] = map var [1..6]++-- from: +-- Martin Mok-Don Lee: Factorization of multivariate polynomials +sparse1 :: Int -> Poly Integer+sparse1 halfk + = (x^2*y^2*z + x*(y^k+z^k) + 3*y + 3*z - 3*z^2 - 2*y^halfk*z^halfk ) + * (x^2*y^2*z^2 + x*(y^k+z^k) - 2*y - 5*z + 4*y^2 + 3*y^halfk*z^halfk ) + where+ k = 2*halfk+ [x,y,z] = map var [1..3]++-- from:+-- Martin Mok-Don Lee: Factorization of multivariate polynomials +sparse2 :: Int -> Poly Integer+sparse2 k + = ( (x*( y^3+2*z^3) + 5*y*z)*(x*(y+4*z)+2) + (2*x-7)*(y^k*z^k-y^(k-1)*z^(k-1)) )+ * ( (x*(3*y^3+4*z^3) + 3*y*z)*(x*(y+3*z)+7) - (3*x+5)*(y^k*z^k-y^(k-1)*z^(k-1)) )+ where+ [x,y,z] = map var [1..3]++--------------------------------------------------------------------------------+++some_polys_F2 :: [Poly (FF 2)]+some_polys_F2 = map mapIntoDomain some_polys_ZZ++some_polys_F3 :: [Poly (FF 3)]+some_polys_F3 = map mapIntoDomain some_polys_ZZ++some_polys_F5 :: [Poly (FF 5)]+some_polys_F5 = map mapIntoDomain some_polys_ZZ++some_polys_GF4 :: [Poly (GF 2 2 "q")]+some_polys_GF4 = map mapIntoDomain some_polys_ZZ++some_polys_GF8 :: [Poly (GF 2 3 "q")]+some_polys_GF8 = map mapIntoDomain some_polys_ZZ++some_polys_GF9 :: [Poly (GF 3 2 "q")]+some_polys_GF9 = map mapIntoDomain some_polys_ZZ++--------------------------------------------------------------------------------+-- TODO: collect examples where the factorization is known++data KnownFactors poly = KnownFactors+ { _poly :: poly+ , _facs :: [(poly,Int)]+ } + deriving (Show,Functor)++-- A bivariate polynomial over F2+-- taken from +-- F. K. Abu Salem: An efficient sparse adaptation of the polytope method over Fp +-- and a record-high binary bivariate factorisation +abuSalemBenchmark = KnownFactors+ { _poly = "x^4120 + x^4118*y^2 + x^3708*y^400 + x^3706*y^402+ x^2781*y^1300 + x^2779*y^1302 + x^1339*y^2700+ x^927*y^3100 + y^4000 + x^7172*y^4167 + x^8349*y^4432+ x^8347*y^4434 + x^6760*y^4567 + x^5833*y^5467+ x^5568*y^7132 + x^11401*y^8599"+ , _facs = [ ("x^5568*y^4432 + x^1339 + x^927*y^400 + y^1300" , 1)+ , ("x^5833*y^4167 + x^2781 + x^2779*y^2 + y^2700" , 1)+ ]+ }+ +--------------------------------------------------------------------------------++reconstructFromFactors :: BaseDomain dom => [(Poly dom, Int)] -> Poly dom +reconstructFromFactors = product . map (uncurry pow)++prop_reconstr_from_factors :: BaseDomain dom => Poly dom -> Bool+prop_reconstr_from_factors p = (p == reconstructFromFactors (factorize p))++reconstr_some_polys :: BaseDomain dom => [Poly dom] -> Bool+reconstr_some_polys list = and (map prop_reconstr_from_factors list)++--------------------------------------------------------------------------------++{-+counting_main = do++ let [x,y,z] = map var [1..3]+ let f = - y^2*z + x^3 + 2*z^3 :: Poly V Integer+ print f+ + let [x,y,z,u,v,w] = map var [1..6]+ let g1 = x*v - y*u + g2 = x*w - z*u + g3 = y*w - z*v+ gs = [g1,g2,g3] :: [Poly V Integer]+-}++{-+ cnts @(FF 5) (map mapIntoDomain gs)+ cntsP @(FF 5) (map mapIntoDomain gs)+-}++{- + putStrLn "==========================\np=2"+ cnt @(FF 2) (mapIntoDomain f)+ cnt @(GF 2 2 "x") (mapIntoDomain f)+ cnt @(GF 2 3 "x") (mapIntoDomain f)+ cnt @(GF 2 4 "x") (mapIntoDomain f)+ cnt @(GF 2 5 "x") (mapIntoDomain f)+ cnt @(GF 2 6 "x") (mapIntoDomain f)+ cnt @(GF 2 7 "x") (mapIntoDomain f)+++ putStrLn "==========================\np=3"+ cnt @(FF 3) (mapIntoDomain f)+ cnt @(GF 3 2 "x") (mapIntoDomain f)+ cnt @(GF 3 3 "x") (mapIntoDomain f)+ cnt @(GF 3 4 "x") (mapIntoDomain f)+ cnt @(GF 3 5 "x") (mapIntoDomain f)+ cnt @(GF 3 6 "x") (mapIntoDomain f)+ cnt @(GF 3 7 "x") (mapIntoDomain f)+-}++{-+ putStrLn "==========================\np=5"+ cntP @(FF 5) (mapIntoDomain f)+ cntP @(GF 5 2 "x") (mapIntoDomain f)+ cntP @(GF 5 3 "x") (mapIntoDomain f)+ cntP @(GF 5 4 "x") (mapIntoDomain f)+ cntP @(GF 5 5 "x") (mapIntoDomain f)+-}++{-+ putStrLn "==========================\np=7"+ cntP @(FF 7) (mapIntoDomain f)+ cntP @(GF 7 2 "x") (mapIntoDomain f)+ cntP @(GF 7 3 "x") (mapIntoDomain f)+ cntP @(GF 7 4 "x") (mapIntoDomain f)+ cntP @(GF 7 5 "x") (mapIntoDomain f)++cnt :: forall domain. FiniteDomain domain => Poly V domain -> IO ()+cnt poly = do+ let cnt = countAffineHypersurface 3 poly+ let q = domainSize (Proxy :: Proxy domain)+ print (q,cnt,divMod (cnt-1) (q-1))++cntP :: forall domain. FiniteDomain domain => Poly V domain -> IO ()+cntP poly = do+ let cnt = countProjectiveHypersurface 3 poly+ let q = domainSize (Proxy :: Proxy domain)+ print (q,cnt)++cnts :: forall domain. FiniteDomain domain => [Poly V domain] -> IO ()+cnts polys = do+ let cnt = countAffineSolutions 6 polys+ let q = domainSize (Proxy :: Proxy domain)+ print (q,cnt,divMod (cnt-1) (q-1))++cntsP :: forall domain. FiniteDomain domain => [Poly V domain] -> IO ()+cntsP polys = do+ let cnt = countProjectiveSolutions 6 polys+ let q = domainSize (Proxy :: Proxy domain)+ print (q,cnt)++-}++--------------------------------------------------------------------------------