├── .ci-install-normaliz.sh ├── .ci-install-pynormaliz.sh ├── .ci-run-tests.sh ├── .clang-format ├── .codecov.yml ├── .coveragerc ├── .github └── workflows │ ├── ci.yml │ └── dist.yml ├── .gitignore ├── .mailmap ├── COPYING ├── GPLv2 ├── MANIFEST.in ├── NormalizModule.cpp ├── PyNormaliz.py ├── README.md ├── doc ├── PyNormaliz.pdf ├── PyNormaliz_Tutorial.ipynb └── PyNormaliz_Tutorial.pdf ├── examples ├── 4x4.py ├── first.py ├── first_enf.py ├── first_long.py ├── first_rational.py ├── getters.py ├── j462.py ├── runexamples.sh └── simple.py ├── setup.cfg ├── setup.py └── tests ├── autom.txt ├── equation-41.txt ├── generic_test.py ├── modify_cone.txt ├── modify_cone_renf.txt ├── must_be_matrices-39.txt ├── quasi_poly-36.txt ├── rational.txt ├── runtests.py ├── segfault-23.txt ├── segfault-27.txt ├── segfault-35.txt ├── segfault-45.txt ├── test_rational_cones.txt ├── vertex_denom-37.txt ├── volume_20.txt └── volume_22.txt /.ci-install-normaliz.sh: -------------------------------------------------------------------------------- 1 | #/usr/bin/env bash 2 | 3 | set -e # exit on error 4 | set -x # print command before execution 5 | 6 | export NMZ_PREFIX=${PWD}/local 7 | export NORMALIZ_LOCAL_DIR=${NMZ_PREFIX} 8 | 9 | # don't pollute the PyNormaliz directory 10 | cd /tmp 11 | 12 | git clone --depth=1 https://github.com/Normaliz/Normaliz 13 | cd Normaliz 14 | 15 | export MAKEFLAGS="-j2" 16 | 17 | # install dependencies 18 | 19 | if [[ $OSTYPE == darwin* ]]; then ## sets paths etc. for Homebrew LLVM 20 | source install_scripts_opt/common.sh 21 | [ "$EANTIC" == "yes" ] && ./install_scripts_opt/install_nmz_mpfr.sh && echo "mpfr complete!" 22 | [ "$EANTIC" == "yes" ] && ./install_scripts_opt/install_nmz_flint.sh && echo "flint complete!" 23 | fi 24 | 25 | [ "$COCOALIB" == "yes" ] && ./install_scripts_opt/install_nmz_cocoa.sh && echo "cocoalib complete!" 26 | [ "$FLINT" == "yes" ] && ./install_scripts_opt/install_nmz_flint.sh && echo "flint complete!" 27 | [ "$EANTIC" == "yes" ] && ./install_scripts_opt/install_nmz_flint.sh && echo "flint complete!" 28 | [ "$EANTIC" == "yes" ] && ./install_scripts_opt/install_nmz_arb.sh && echo "arb complete!" 29 | [ "$EANTIC" == "yes" ] && ./install_scripts_opt/install_nmz_e-antic.sh && echo "e-antic complete!" 30 | [ "$NAUTY" == "yes" ] && ./install_scripts_opt/install_nmz_nauty.sh && echo "nauty complete!" 31 | 32 | # finally install Normaliz 33 | ./bootstrap.sh 34 | export CPPFLAGS="${CPPFLAGS} -I${NMZ_PREFIX}/include" 35 | export LDFLAGS="${LDFLAGS} -L${NMZ_PREFIX}/lib" 36 | ./configure --prefix=${NMZ_PREFIX} 37 | make 38 | echo "//////" 39 | echo ${NMZ_PREFIX} 40 | make install 41 | cd .. 42 | -------------------------------------------------------------------------------- /.ci-install-pynormaliz.sh: -------------------------------------------------------------------------------- 1 | #/usr/bin/env bash 2 | 3 | set -e # exit on error 4 | set -x # print command before execution 5 | 6 | export NMZ_PREFIX=${PWD}/local 7 | export NORMALIZ_LOCAL_DIR=${NMZ_PREFIX} 8 | 9 | mkdir -p /tmp/Normaliz/local 10 | cp -r ${NMZ_PREFIX} /tmp/Normaliz 11 | 12 | mkdir -p /tmp/Normaliz/PyNormaliz 13 | cp -r * /tmp/Normaliz/PyNormaliz 14 | 15 | # don't pollute the PyNormaliz directory 16 | cd /tmp 17 | cd Normaliz 18 | 19 | if [[ $OSTYPE == darwin* ]]; then ## sets paths etc. for Homebrew LLVM 20 | source install_scripts_opt/common.sh 21 | fi 22 | 23 | ./install_pynormaliz.sh --user 24 | 25 | -------------------------------------------------------------------------------- /.ci-run-tests.sh: -------------------------------------------------------------------------------- 1 | #/usr/bin/env bash 2 | 3 | set -e # exit on error 4 | set -x # print command before execution 5 | 6 | cd /tmp/Normaliz/PyNormaliz 7 | python3 tests/runtests.py 8 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | AlignConsecutiveDeclarations: true 2 | AlignTrailingComments: true 3 | AllowShortBlocksOnASingleLine: false 4 | AllowShortFunctionsOnASingleLine: false 5 | AllowShortIfStatementsOnASingleLine: false 6 | AllowShortLoopsOnASingleLine: false 7 | BinPackArguments: true 8 | BinPackParameters: false 9 | BreakBeforeBraces: Stroustrup 10 | ColumnLimit: 78 11 | Cpp11BracedListStyle: true 12 | IndentCaseLabels: true 13 | IndentWidth: 4 14 | MaxEmptyLinesToKeep: 2 15 | PointerBindsToType: Left 16 | SpacesBeforeTrailingComments: 4 17 | UseTab: Never 18 | SortIncludes: false 19 | SpacesInAngles: true 20 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | precision: 2 3 | round: down 4 | range: "70...100" 5 | 6 | status: 7 | project: no 8 | patch: no 9 | changes: no 10 | 11 | comment: 12 | layout: "header, diff, changes, tree" 13 | behavior: default 14 | 15 | ignore: 16 | - "local" 17 | - "nmz_opt_lib" 18 | - "test" 19 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | # See 2 | # and 3 | # 4 | [run] 5 | omit = tests 6 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | 3 | on: 4 | - push 5 | - pull_request 6 | 7 | jobs: 8 | our-installation: 9 | runs-on: ubuntu-latest 10 | env: 11 | EANTIC: yes 12 | NAUTY: yes 13 | COCOALIB: yes 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: "Install prerequisites and Normaliz" 17 | run: | 18 | # sudo apt-get install libgmp-dev libpython3-dev python3-setuptools 19 | # (packages already installed in GitHub's Ubuntu) 20 | ./.ci-install-normaliz.sh 21 | - name: "Install PyNormaliz" 22 | run: | 23 | ./.ci-install-pynormaliz.sh 24 | - name: "Run tests" 25 | run: | 26 | ./.ci-run-tests.sh 27 | 28 | no-eantic: 29 | runs-on: ubuntu-latest 30 | env: 31 | EANTIC: no 32 | NAUTY: yes 33 | COCOALIB: yes 34 | steps: 35 | - uses: actions/checkout@v2 36 | - name: "Install prerequisites and Normaliz" 37 | run: | 38 | # sudo apt-get install libgmp-dev libpython3-dev python3-setuptools 39 | # (packages already installed in GitHub's Ubuntu) 40 | ./.ci-install-normaliz.sh 41 | - name: "Install PyNormaliz" 42 | run: | 43 | ./.ci-install-pynormaliz.sh 44 | - name: "Run tests" 45 | run: | 46 | ./.ci-run-tests.sh 47 | 48 | mac-os: 49 | runs-on: macos-13 50 | env: 51 | EANTIC: yes 52 | NAUTY: yes 53 | COCOALIB: yes 54 | steps: 55 | - uses: actions/checkout@v2 56 | - uses: actions/setup-python@v2 57 | with: 58 | python-version: '3.7' 59 | - name: "Setup compiler and build automake" 60 | run: | 61 | brew reinstall llvm automake 62 | - name: "Install Python prerequisites" 63 | run: | 64 | pip3 install coverage 65 | pip3 install setuptools 66 | - name: "Install Normaliz" 67 | run: | 68 | ./.ci-install-normaliz.sh 69 | - name: "Install PyNormaliz" 70 | run: | 71 | ./.ci-install-pynormaliz.sh 72 | - name: "Run tests" 73 | run: | 74 | ./.ci-run-tests.sh 75 | 76 | # eantic-nauty: 77 | # runs-on: ubuntu-latest 78 | # env: 79 | # EANTIC: yes 80 | # NAUTY: yes 81 | # COCOALIB: no 82 | # steps: 83 | # 84 | # - uses: actions/checkout@v2 85 | # - name: "Install prerequisites and Normaliz" 86 | # run: | 87 | # sudo apt-get install libgmp-dev libflint-dev 88 | # export PIP=$(which pip) # workaround so that sudo uses correct pip 89 | # pip install coverage 90 | # pip3 install coverage 91 | # pip install setuptools 92 | # pip3 install setuptools 93 | # ./.ci-install-normaliz.sh 94 | # - name: "Install PyNormaliz" 95 | # run: | 96 | # export CFLAGS="$CFLAGS --coverage" 97 | # export PYTHONPATH="$PWD" 98 | # export NMZ_PREFIX=${PWD}/local 99 | # export NORMALIZ_LOCAL_DIR=${NMZ_PREFIX} 100 | # python setup.py build_ext --inplace 101 | # - name: "Run tests" 102 | # run: | 103 | # export OMP_NUM_THREADS=4 104 | # # coverage run tests/runtests.py 105 | # python tests/runtests.py 106 | # #sudo $PIP install --no-index --no-deps -v dist/PyNormaliz-*.tar.gz 107 | # sudo $PIP install --no-deps -v dist/PyNormaliz-*.tar.gz 108 | # python -c "import PyNormaliz" 109 | # - name: "Upload coverage data to Codecov" 110 | # uses: codecov/codecov-action@v1 111 | -------------------------------------------------------------------------------- /.github/workflows/dist.yml: -------------------------------------------------------------------------------- 1 | name: Distributions 2 | 3 | on: 4 | push: 5 | pull_request: 6 | workflow_dispatch: 7 | 8 | concurrency: 9 | # Cancel previous runs of this workflow for the same branch 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | 15 | sdists_for_pypi: 16 | name: Build sdist (and upload to PyPI on release tags) 17 | runs-on: ubuntu-latest 18 | env: 19 | CAN_DEPLOY: ${{ secrets.PYPI_PASSWORD != '' }} 20 | steps: 21 | - uses: actions/checkout@v4 22 | - uses: actions/setup-python@v4 23 | - name: make sdist 24 | run: | 25 | python3 -m pip install build 26 | python3 -m build --sdist 27 | - uses: actions/upload-artifact@v4 28 | with: 29 | path: "dist/*.tar.gz" 30 | name: dist 31 | - uses: pypa/gh-action-pypi-publish@release/v1 32 | with: 33 | user: ${{ secrets.PYPI_USERNAME }} 34 | password: ${{ secrets.PYPI_PASSWORD }} 35 | skip_existing: true 36 | verbose: true 37 | if: env.CAN_DEPLOY == 'true' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags') 38 | 39 | build_wheels: 40 | name: Build wheels on ${{ matrix.os }}, arch ${{ matrix.arch }} 41 | runs-on: ${{ matrix.os }} 42 | needs: sdists_for_pypi 43 | strategy: 44 | fail-fast: false 45 | matrix: 46 | include: 47 | - os: ubuntu-latest 48 | arch: x86_64 49 | - os: ubuntu-latest 50 | arch: i686 51 | - os: ubuntu-24.04-arm 52 | arch: aarch64 53 | - os: macos-13 54 | arch: x86_64 55 | - os: macos-14 56 | arch: arm64 57 | env: 58 | # SPKGs to install as system packages 59 | SPKGS: _bootstrap _prereq 60 | # Non-Python packages to install as spkgs 61 | TARGETS_PRE: gmp mpfr normaliz 62 | # Disable building PyPy wheels on all platforms 63 | # Disable musllinux until #33083 provides alpine package information 64 | CIBW_SKIP: "pp* *-musllinux*" 65 | # 66 | CIBW_ARCHS: ${{ matrix.arch }} 67 | # https://cibuildwheel.readthedocs.io/en/stable/options/#requires-python 68 | CIBW_PROJECT_REQUIRES_PYTHON: ">=3.9" 69 | # Environment during wheel build 70 | CIBW_ENVIRONMENT: "PATH=$(pwd)/local/bin:$PATH CPATH=$(pwd)/local/include:$CPATH LIBRARY_PATH=$(pwd)/local/lib:$LIBRARY_PATH LD_LIBRARY_PATH=$(pwd)/local/lib:$LD_LIBRARY_PATH PKG_CONFIG_PATH=$(pwd)/local/share/pkgconfig:$PKG_CONFIG_PATH ACLOCAL_PATH=/usr/share/aclocal" 71 | # Use 'build', not 'pip wheel' 72 | CIBW_BUILD_FRONTEND: build 73 | steps: 74 | - uses: actions/checkout@v4 75 | with: 76 | repository: passagemath/passagemath 77 | ref: main 78 | 79 | - uses: actions/download-artifact@v4 80 | with: 81 | name: dist 82 | path: dist 83 | 84 | - uses: actions/setup-python@v5 85 | # As of 2024-02-03, the macOS M1 runners do not have preinstalled python or pipx. 86 | # Installing pipx follows the approach of https://github.com/pypa/cibuildwheel/pull/1743 87 | id: python 88 | with: 89 | python-version: "3.8 - 3.12" 90 | update-environment: false 91 | 92 | - name: Build platform wheels 93 | # We build the wheel from the sdist. 94 | # But we must run cibuildwheel with the unpacked source directory, not a tarball, 95 | # so that SAGE_ROOT is copied into the build containers. 96 | # 97 | # In the CIBW_BEFORE_ALL phase, we install libraries using the Sage distribution. 98 | # https://cibuildwheel.readthedocs.io/en/stable/options/#before-all 99 | run: | 100 | "${{ steps.python.outputs.python-path }}" -m pip install pipx 101 | export PATH=build/bin:$PATH 102 | export CIBW_BEFORE_ALL="( $(sage-print-system-package-command debian --yes --no-install-recommends install $(sage-get-system-packages debian $SPKGS)) || $(sage-print-system-package-command fedora --yes --no-install-recommends install $(sage-get-system-packages fedora $SPKGS | sed s/pkg-config/pkgconfig/)) || ( $(sage-print-system-package-command homebrew --yes --no-install-recommends install $(sage-get-system-packages homebrew $SPKGS)) || $(sage-print-system-package-command alpine --yes --no-install-recommends install $(sage-get-system-packages alpine $SPKGS)) || echo error ignored) ) && ./bootstrap && ./configure --enable-build-as-root --enable-fat-binary && MAKE=\"make -j6\" make V=0 $TARGETS_PRE" 103 | mkdir -p unpacked 104 | for pkg in pynormaliz; do 105 | (cd unpacked && tar xfz - ) < dist/$pkg*.tar.gz 106 | "${{ steps.python.outputs.python-path }}" -m pipx run cibuildwheel==2.18.0 unpacked/$pkg* 107 | done 108 | 109 | - uses: actions/upload-artifact@v4 110 | with: 111 | name: ${{ matrix.os }}-${{ matrix.arch }}-wheels 112 | path: ./wheelhouse/*.whl 113 | 114 | pypi-publish: 115 | # This needs to be a separate job because pypa/gh-action-pypi-publish cannot run on macOS 116 | # https://github.com/pypa/gh-action-pypi-publish 117 | name: Upload wheels to PyPI 118 | needs: build_wheels 119 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') 120 | runs-on: ubuntu-latest 121 | env: 122 | CAN_DEPLOY: ${{ secrets.PYPI_PASSWORD != '' }} 123 | steps: 124 | 125 | - uses: actions/download-artifact@v4 126 | with: 127 | pattern: "*-*-wheels" 128 | path: wheelhouse 129 | merge-multiple: true 130 | 131 | - name: Publish package distributions to PyPI 132 | uses: pypa/gh-action-pypi-publish@release/v1 133 | with: 134 | user: ${{ secrets.PYPI_USERNAME }} 135 | password: ${{ secrets.PYPI_PASSWORD }} 136 | packages_dir: wheelhouse/ 137 | skip_existing: true 138 | verbose: true 139 | if: env.CAN_DEPLOY == 'true' 140 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *cpython* 3 | PyNormaliz.so 4 | dist 5 | MANIFEST 6 | *.pyc 7 | *~ 8 | PyNormaliz.egg-info/* 9 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Richard Sieg 2 | Sebastian Gutsche 3 | Winfried Bruns 4 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) Sebastian Gutsche sebastian.gutsche@gmail.com 2 | 3 | This program is free software; you can redistribute it and/or 4 | modify it under the terms of the GNU General Public License 5 | as published by the Free Software Foundation; either version 2 6 | of the License, or (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program; if not, write to the Free Software 15 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | -------------------------------------------------------------------------------- /GPLv2: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include COPYING 2 | include GPLv2 3 | include NormalizModule.cpp 4 | include setup.py 5 | include README.md 6 | include examples/* 7 | include doc/* 8 | include tests/* 9 | -------------------------------------------------------------------------------- /NormalizModule.cpp: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * 3 | * Include 4 | * 5 | ***************************************************************************/ 6 | 7 | #include 8 | 9 | #include 10 | using std::string; 11 | 12 | /* 13 | #include 14 | #include 15 | #include 16 | #include 17 | */ 18 | 19 | #include 20 | 21 | #ifdef ENFNORMALIZ 22 | using eantic::renf_elem_class; 23 | using eantic::renf_class; 24 | #endif 25 | 26 | using libnormaliz::Cone; 27 | // using libnormaliz::ConeProperty; 28 | using libnormaliz::ConeProperties; 29 | using libnormaliz::Sublattice_Representation; 30 | using libnormaliz::Type::InputType; 31 | using libnormaliz::AutomorphismGroup; 32 | using libnormaliz::Matrix; 33 | 34 | #ifdef LIBNORMALIZ_DYNAMIC_BITSET_H 35 | using libnormaliz::dynamic_bitset; 36 | #else 37 | typedef boost::dynamic_bitset<> dynamic_bitset; 38 | #endif 39 | 40 | #include 41 | using std::map; 42 | using std::pair; 43 | using std::vector; 44 | 45 | #include 46 | 47 | typedef int py_size_t; 48 | 49 | #include 50 | 51 | /*************************************************************************** 52 | * 53 | * Macros for exception handling 54 | * 55 | ***************************************************************************/ 56 | 57 | #define FUNC_BEGIN try { 58 | 59 | #define FUNC_END \ 60 | } \ 61 | catch (libnormaliz::InterruptException & e) \ 62 | { \ 63 | libnormaliz::nmz_interrupted = false; \ 64 | PyErr_SetString(PyExc_KeyboardInterrupt, \ 65 | "interrupted Normaliz Computation"); \ 66 | PyErr_SetInterrupt(); \ 67 | PyErr_CheckSignals(); \ 68 | return NULL; \ 69 | } \ 70 | catch (libnormaliz::NormalizException & e) \ 71 | { \ 72 | PyErr_SetString(NormalizError, e.what()); \ 73 | return NULL; \ 74 | } \ 75 | catch (std::exception & e) \ 76 | { \ 77 | PyErr_SetString(PyNormaliz_cppError, e.what()); \ 78 | return NULL; \ 79 | } 80 | 81 | 82 | class PyNormalizInputException : public std::exception { 83 | private: 84 | std::string message_; 85 | 86 | public: 87 | explicit PyNormalizInputException(const std::string& message); 88 | virtual const char* what() const throw() 89 | { 90 | return message_.c_str(); 91 | } 92 | std::string what_message() const throw() 93 | { 94 | return message_; 95 | } 96 | }; 97 | 98 | 99 | PyNormalizInputException::PyNormalizInputException(const std::string& message) 100 | : message_(message) 101 | { 102 | } 103 | 104 | /*************************************************************************** 105 | * 106 | * Signal handling 107 | * 108 | ***************************************************************************/ 109 | 110 | static void signal_handler(int signal) 111 | { 112 | libnormaliz::nmz_interrupted = true; 113 | } 114 | 115 | // helper class implementing RAII pattern for our custom SIGINT handler; 116 | // it helps ensure we *always* restore the signal handler inside a 117 | // FUNC_BEGIN / FUNC_END block. 118 | class TempSignalHandler { 119 | PyOS_sighandler_t original_handler; 120 | public: 121 | TempSignalHandler() { 122 | original_handler = PyOS_setsig(SIGINT, signal_handler); 123 | } 124 | 125 | ~TempSignalHandler() { 126 | PyOS_setsig(SIGINT, original_handler); 127 | } 128 | }; 129 | 130 | /*************************************************************************** 131 | * 132 | * Static objects 133 | * 134 | ***************************************************************************/ 135 | 136 | 137 | static PyObject* NormalizError; 138 | static PyObject* PyNormaliz_cppError; 139 | static const char* cone_name = "Cone"; 140 | static const char* cone_name_long = "Cone"; 141 | static const char* cone_name_renf = "Cone"; 142 | 143 | static PyObject* RationalHandler = NULL; 144 | static PyObject* FloatHandler = NULL; 145 | 146 | #ifdef ENFNORMALIZ 147 | static PyObject* NumberfieldElementHandler = NULL; 148 | #endif 149 | 150 | static PyObject* VectorHandler = NULL; 151 | static PyObject* MatrixHandler = NULL; 152 | 153 | /*************************************************************************** 154 | * 155 | * Call func on one argument 156 | * 157 | ***************************************************************************/ 158 | 159 | static PyObject* CallPythonFuncOnOneArg(PyObject* function, PyObject* single_arg) 160 | { 161 | PyObject* single_arg_tuple = PyTuple_Pack(1, single_arg); 162 | PyObject* return_obj = PyObject_CallObject(function, single_arg_tuple); 163 | Py_DecRef(single_arg); 164 | Py_DecRef(single_arg_tuple); 165 | return return_obj; 166 | } 167 | 168 | /*************************************************************************** 169 | * 170 | * Compiler version control 171 | * 172 | ***************************************************************************/ 173 | 174 | #if PY_MAJOR_VERSION >= 3 175 | #define string_check PyUnicode_Check 176 | #else 177 | #define string_check PyString_Check 178 | #endif 179 | 180 | #ifndef NMZ_RELEASE 181 | static_assert( 182 | false, 183 | "Your Normaliz version (unknown) is too old! Update to 3.10.4 or newer."); 184 | #endif 185 | #if NMZ_RELEASE < 31004 186 | static_assert(false, 187 | "Your Normaliz version is too old! Update to 3.10.4 or newer."); 188 | #endif 189 | 190 | /*************************************************************************** 191 | * 192 | * Python-C data conversion functions 193 | * 194 | ***************************************************************************/ 195 | 196 | static string PyUnicodeToString(PyObject* in) 197 | { 198 | if (!string_check(in)) { 199 | throw PyNormalizInputException("input must be a string"); 200 | return NULL; 201 | } 202 | #if PY_MAJOR_VERSION >= 3 203 | string out = ""; 204 | int length = PyUnicode_GET_LENGTH(in); 205 | for (int i = 0; i < length; i++) { 206 | out += PyUnicode_READ_CHAR(in, i); 207 | } 208 | return out; 209 | #else 210 | char* out = PyString_AsString(in); 211 | return string(out); 212 | #endif 213 | } 214 | 215 | static PyObject* StringToPyUnicode(const string &in) 216 | { 217 | #if PY_MAJOR_VERSION >= 3 218 | return PyUnicode_FromString(in.c_str()); 219 | #else 220 | return PyString_FromString(in.c_str()); 221 | #endif 222 | } 223 | 224 | // Boolean conversion 225 | 226 | static inline PyObject* BoolToPyBool(bool in) 227 | { 228 | if (in) 229 | Py_RETURN_TRUE; 230 | Py_RETURN_FALSE; 231 | } 232 | 233 | // Converting MPZ's to PyLong and back via strings. Worst possible solution 234 | // ever. 235 | static bool PyNumberToNmz(PyObject*, mpz_class&); 236 | 237 | static bool PyNumberToNmz(PyObject* in, mpq_class& out) 238 | { 239 | if (PyFloat_Check(in)) { 240 | throw PyNormalizInputException("PyFloat not allowed in PyNormaliz input. Must be encoded as string."); 241 | return true; 242 | } 243 | #if PY_MAJOR_VERSION < 3 244 | if (PyInt_Check(in)) { 245 | out = PyInt_AsLong(in); 246 | return true; 247 | } 248 | #endif 249 | if (PyLong_Check(in)) { 250 | mpz_class out_tmp; 251 | bool check = PyNumberToNmz(in, out_tmp); 252 | if (!check) { 253 | return false; 254 | } 255 | out = mpq_class(out_tmp); 256 | return true; 257 | } 258 | if (PyList_CheckExact(in) || PyTuple_CheckExact(in)) { 259 | PyObject* py_num = PySequence_GetItem(in, 0); 260 | PyObject* py_denom = PySequence_GetItem(in, 1); 261 | mpz_class num; 262 | if (!PyNumberToNmz(py_num, num)) { 263 | return false; 264 | } 265 | mpz_class denom; 266 | if (!PyNumberToNmz(py_denom, denom)) { 267 | return false; 268 | } 269 | out = mpq_class(num, denom); 270 | return true; 271 | } 272 | PyObject* in_as_string = PyObject_Str(in); 273 | string s = PyUnicodeToString(in_as_string); 274 | // int check = out.set_str(s.c_str(), 10); 275 | libnormaliz::string2coeff(out,s); 276 | 277 | return true; 278 | } 279 | 280 | static bool PyNumberToNmz(PyObject* in, mpz_class& out) 281 | { 282 | #if PY_MAJOR_VERSION < 3 283 | if (PyInt_Check(in)) { 284 | out = PyInt_AsLong(in); 285 | return true; 286 | } 287 | #endif 288 | if (!PyLong_Check(in)) { 289 | throw PyNormalizInputException( 290 | "input coeff must be a PyInt or PyLong"); 291 | } 292 | int overflow; 293 | long input_long = PyLong_AsLongAndOverflow(in, &overflow); 294 | if (overflow == 0) { 295 | out = mpz_class(input_long); 296 | return true; 297 | } 298 | PyObject* in_as_string = PyObject_Str(in); 299 | string s = PyUnicodeToString(in_as_string); 300 | out.set_str(s.c_str(), 10); 301 | return true; 302 | } 303 | 304 | static PyObject* NmzToPyNumber(const mpz_class in) 305 | { 306 | if (in.fits_slong_p()) { 307 | return PyLong_FromLong(in.get_si()); 308 | } 309 | 310 | // in Python 2, the first argument to PyLong_FromString is not const, thus 311 | // we need to perform a const cast here. 312 | string mpz_as_string = in.get_str(16); 313 | char* mpz_as_c_string = const_cast< char* >(mpz_as_string.c_str()); 314 | return PyLong_FromString(mpz_as_c_string, NULL, 16); 315 | } 316 | 317 | static PyObject* NmzToPyNumber(const mpq_class in) 318 | { 319 | PyObject* out_list = PyList_New(2); 320 | PyList_SetItem(out_list, 0, NmzToPyNumber(in.get_num())); 321 | PyList_SetItem(out_list, 1, NmzToPyNumber(in.get_den())); 322 | if (RationalHandler != NULL) 323 | out_list = CallPythonFuncOnOneArg(RationalHandler, out_list); 324 | return out_list; 325 | } 326 | 327 | static bool PyNumberToNmz(PyObject* in, long long& out) 328 | { 329 | int overflow; 330 | out = PyLong_AsLongLongAndOverflow(in, &overflow); 331 | if (overflow == -1) 332 | throw PyNormalizInputException( 333 | "Cannot store input coefficient in long long"); 334 | return true; 335 | } 336 | 337 | static PyObject* NmzToPyNumber(unsigned int in) 338 | { 339 | return PyLong_FromUnsignedLong(in); 340 | } 341 | 342 | static PyObject* NmzToPyNumber(unsigned long in) 343 | { 344 | return PyLong_FromUnsignedLong(in); 345 | } 346 | 347 | static PyObject* NmzToPyNumber(int in) 348 | { 349 | return PyLong_FromLong(in); 350 | } 351 | 352 | static PyObject* NmzToPyNumber(long in) 353 | { 354 | return PyLong_FromLong(in); 355 | } 356 | 357 | static PyObject* NmzToPyNumber(long long in) 358 | { 359 | return PyLong_FromLongLong(in); 360 | } 361 | 362 | static PyObject* NmzToPyNumber(double in) 363 | { 364 | PyObject* x = PyFloat_FromDouble(in); 365 | if(FloatHandler == NULL) 366 | return x; 367 | 368 | return CallPythonFuncOnOneArg(FloatHandler, x); 369 | } 370 | 371 | template < typename Integer > 372 | static PyObject* NmzVectorToPyList(const vector< Integer >& in, 373 | bool do_callback = true); 374 | 375 | #ifdef ENFNORMALIZ 376 | static PyObject* NmzToPyNumber(const renf_elem_class &in) 377 | { 378 | // std::cout << "IIIII " << in << std::endl; 379 | vector< mpz_class > output_nums = in.get_num_vector(); 380 | mpz_class output_den = in.get_den(); 381 | vector< mpz_class > denoms(output_nums.size(), output_den); 382 | for(size_t i=0; i< output_nums.size(); ++i){ 383 | mpq_class quot = output_nums[i]; 384 | quot /= output_den; 385 | output_nums[i] = quot.get_num(); 386 | denoms[i] = quot.get_den(); 387 | } 388 | /*std::cout << "NNN "; 389 | for( size_t i = 0; i< output_nums.size(); ++i) 390 | std::cout << output_nums[i] << " "; 391 | std::cout << std::endl; 392 | std::cout << "DDD "; 393 | for( size_t i = 0; i< output_nums.size(); ++i) 394 | std::cout << denoms[i] << " "; 395 | std::cout << std::endl;*/ 396 | // PyObject* denom_py = NmzToPyNumber(output_den); 397 | PyObject* out_list = PyList_New(output_nums.size()); 398 | for (size_t i = 0; i < output_nums.size(); i++) { 399 | PyObject* current = PyList_New(2); 400 | PyList_SetItem(current, 0, NmzToPyNumber(output_nums[i])); 401 | // Py_IncRef(denom_py); 402 | PyList_SetItem(current, 1, NmzToPyNumber(denoms[i])); 403 | if (RationalHandler != NULL) 404 | current = CallPythonFuncOnOneArg(RationalHandler, current); 405 | PyList_SetItem(out_list, i, current); 406 | } 407 | // Py_DecRef(denom_py); 408 | if (NumberfieldElementHandler != NULL) 409 | out_list = CallPythonFuncOnOneArg(NumberfieldElementHandler, out_list); 410 | return out_list; 411 | } 412 | #endif 413 | 414 | PyObject* NmzToPyNumber(const dynamic_bitset& in) 415 | { 416 | size_t len = in.size(); 417 | PyObject* result = PyList_New(len); 418 | for (size_t i = 0; i < len; i++) { 419 | PyList_SetItem(result, i, NmzToPyNumber(in[i] ? 1 : 0)); 420 | } 421 | return result; 422 | } 423 | 424 | template < typename Integer > 425 | static bool PyListToNmz(vector< Integer >& out, PyObject* in) 426 | { 427 | if (!PySequence_Check(in)) 428 | throw PyNormalizInputException("Input list is not a sequence"); 429 | const int n = PySequence_Size(in); 430 | out.resize(n); 431 | for (int i = 0; i < n; ++i) { 432 | PyObject* tmp = PySequence_GetItem(in, i); 433 | if (!PyNumberToNmz(tmp, out[i])) 434 | return false; 435 | } 436 | return true; 437 | } 438 | 439 | template < typename Integer > 440 | static bool PyIntMatrixToNmz(vector< vector< Integer > >& out, PyObject* in) 441 | { 442 | if (!PySequence_Check(in)) 443 | throw PyNormalizInputException("Input matrix is not a sequence"); 444 | const int nr = PySequence_Size(in); 445 | out.resize(nr); 446 | for (int i = 0; i < nr; ++i) { 447 | bool okay = PyListToNmz(out[i], PySequence_GetItem(in, i)); 448 | if (!okay) 449 | return false; 450 | } 451 | return true; 452 | } 453 | 454 | #ifdef ENFNORMALIZ 455 | template < typename NumberField, typename NumberFieldElem > 456 | static bool prepare_nf_input(vector< vector< NumberFieldElem > >& out, 457 | PyObject* in, 458 | NumberField* nf) 459 | { 460 | if (!PySequence_Check(in)) 461 | throw PyNormalizInputException("Number field data is not a list"); 462 | const int nr = PySequence_Size(in); 463 | out.resize(nr); 464 | for (int i = 0; i < nr; ++i) { 465 | PyObject* current_row = PySequence_GetItem(in, i); 466 | int current_length = PySequence_Size(current_row); 467 | out[i].resize(current_length); 468 | for (int j = 0; j < current_length; j++) { 469 | PyObject* current_element = PySequence_GetItem(current_row, j); 470 | bool current_res; 471 | NumberFieldElem current_elem; 472 | 473 | if (PyList_CheckExact(current_element) || PyTuple_CheckExact(current_element)) { 474 | vector< mpq_class > current_vector; 475 | current_res = PyListToNmz(current_vector, current_element); 476 | if (!current_res) { 477 | return false; 478 | } 479 | current_elem = NumberFieldElem(*nf, current_vector); 480 | } 481 | if (string_check(current_element)) { 482 | current_elem = NumberFieldElem(*nf,PyUnicodeToString(current_element)); 483 | // current_elem = PyUnicodeToString(current_element); 484 | } 485 | if (PyFloat_Check(current_element)){ 486 | throw PyNormalizInputException("Nonintegral numbers must be given as strings"); 487 | } 488 | if (PyLong_Check(current_element)) { 489 | mpq_class tmp; 490 | current_res = PyNumberToNmz(current_element, tmp); 491 | if (!current_res) { 492 | return false; 493 | } 494 | current_elem = tmp; 495 | } 496 | #if PY_MAJOR_VERSION < 3 497 | if (PyInt_Check(current_element)) { 498 | current_elem = PyInt_AsLong(current_element); 499 | } 500 | #endif 501 | out[i][j] = current_elem; 502 | } 503 | } 504 | 505 | return true; 506 | } 507 | #endif 508 | 509 | template < typename Integer > 510 | static bool PyInputToNmz(vector< vector< Integer > >& out, PyObject* in) 511 | { 512 | if (PyIntMatrixToNmz(out, in)) 513 | return true; 514 | out.resize(1); 515 | if (PyListToNmz(out[0], in)) { 516 | return true; 517 | } 518 | throw PyNormalizInputException( 519 | "Input could not be converted to vector or list"); 520 | } 521 | 522 | template < typename Integer > 523 | static PyObject* NmzVectorToPyList(const vector< Integer >& in, bool do_callback) 524 | { 525 | PyObject* vector; 526 | const size_t n = in.size(); 527 | vector = PyList_New(n); 528 | for (size_t i = 0; i < n; ++i) { 529 | PyList_SetItem(vector, i, NmzToPyNumber(in[i])); 530 | } 531 | if (do_callback && VectorHandler != NULL) 532 | vector = CallPythonFuncOnOneArg(VectorHandler, vector); 533 | return vector; 534 | } 535 | 536 | template < typename Integer > 537 | static PyObject* NmzMatrixToPyList(const vector< vector< Integer > >& in) 538 | { 539 | PyObject* matrix; 540 | const size_t n = in.size(); 541 | matrix = PyList_New(n); 542 | for (size_t i = 0; i < n; ++i) { 543 | PyList_SetItem(matrix, i, NmzVectorToPyList(in[i])); 544 | } 545 | if (MatrixHandler != NULL) 546 | matrix = CallPythonFuncOnOneArg(MatrixHandler, matrix); 547 | return matrix; 548 | } 549 | 550 | static PyObject* NmzHilbertSeriesToPyList(const libnormaliz::HilbertSeries& HS, 551 | bool is_HSOP) 552 | { 553 | PyObject* return_list = PyList_New(3); 554 | if (is_HSOP) { 555 | PyList_SetItem(return_list, 0, NmzVectorToPyList(HS.getHSOPNum())); 556 | PyList_SetItem( 557 | return_list, 1, 558 | NmzVectorToPyList(libnormaliz::to_vector(HS.getHSOPDenom()))); 559 | PyList_SetItem(return_list, 2, NmzToPyNumber(HS.getShift())); 560 | } 561 | else { 562 | PyList_SetItem(return_list, 0, NmzVectorToPyList(HS.getNum())); 563 | PyList_SetItem( 564 | return_list, 1, 565 | NmzVectorToPyList(libnormaliz::to_vector(HS.getDenom()))); 566 | PyList_SetItem(return_list, 2, NmzToPyNumber(HS.getShift())); 567 | } 568 | return return_list; 569 | } 570 | 571 | template < typename Integer > 572 | static PyObject* NmzWeightedEhrhartSeriesToPyList( 573 | const std::pair< libnormaliz::HilbertSeries, Integer >& HS) 574 | { 575 | PyObject* return_list = PyList_New(4); 576 | PyList_SetItem(return_list, 0, NmzVectorToPyList(HS.first.getNum())); 577 | PyList_SetItem( 578 | return_list, 1, 579 | NmzVectorToPyList(libnormaliz::to_vector(HS.first.getDenom()))); 580 | PyList_SetItem(return_list, 2, NmzToPyNumber(HS.first.getShift())); 581 | PyList_SetItem(return_list, 3, NmzToPyNumber(HS.second)); 582 | return return_list; 583 | } 584 | 585 | template < typename Integer > 586 | static PyObject* 587 | NmzHilbertQuasiPolynomialToPyList(const libnormaliz::HilbertSeries& HS) 588 | { 589 | vector< vector< Integer > > HQ = HS.getHilbertQuasiPolynomial(); 590 | const size_t n = HS.getPeriod(); 591 | PyObject* return_list = PyList_New(n + 1); 592 | for (size_t i = 0; i < n; ++i) { 593 | PyList_SetItem(return_list, i, NmzVectorToPyList(HQ[i])); 594 | } 595 | PyList_SetItem(return_list, n, 596 | NmzToPyNumber(HS.getHilbertQuasiPolynomialDenom())); 597 | return return_list; 598 | } 599 | 600 | template < typename Integer > 601 | static PyObject* NmzWeightedEhrhartQuasiPolynomialToPyList( 602 | const libnormaliz::IntegrationData& int_data) 603 | { 604 | vector< vector< Integer > > ehrhart_qp = 605 | int_data.getWeightedEhrhartQuasiPolynomial(); 606 | const size_t n = ehrhart_qp.size(); 607 | PyObject* return_list = PyList_New(n + 1); 608 | for (size_t i = 0; i < n; ++i) { 609 | PyList_SetItem(return_list, i, NmzVectorToPyList(ehrhart_qp[i])); 610 | } 611 | PyList_SetItem( 612 | return_list, n, 613 | NmzToPyNumber(int_data.getWeightedEhrhartQuasiPolynomialDenom())); 614 | return return_list; 615 | } 616 | 617 | template < typename Integer > 618 | static PyObject* NmzTriangleListToPyList( 619 | const pair >, libnormaliz::Matrix >& in) 620 | { 621 | const size_t n = in.first.size(); 622 | PyObject* M = PyList_New(n); 623 | for (size_t i = 0; i < n; ++i) { 624 | // convert the pair 625 | PyObject* triple = PyList_New(3); 626 | PyList_SetItem(triple, 0, 627 | NmzVectorToPyList< libnormaliz::key_t >(in.first[i].key)); 628 | PyList_SetItem(triple, 1, NmzToPyNumber(in.first[i].vol)); 629 | PyList_SetItem(triple, 2, NmzToPyNumber(libnormaliz::bool_to_bitset(in.first[i].Excluded))); 630 | PyList_SetItem(M, i, triple); 631 | } 632 | 633 | PyObject* Tr = PyList_New(2); 634 | PyList_SetItem(Tr, 0,M); 635 | PyList_SetItem(Tr, 1,NmzMatrixToPyList(in.second.get_elements())); 636 | return Tr; 637 | } 638 | 639 | template < typename Integer > 640 | static PyObject* NmzPairVectorToPyList( 641 | const vector< pair< vector< libnormaliz::key_t >, Integer > >& in) 642 | { 643 | const size_t n = in.size(); 644 | PyObject* M = PyList_New(n); 645 | for (size_t i = 0; i < n; ++i) { 646 | // convert the pair 647 | PyObject* pair = PyList_New(2); 648 | PyList_SetItem(pair, 0, 649 | NmzVectorToPyList< libnormaliz::key_t >(in[i].first)); 650 | PyList_SetItem(pair, 1, NmzToPyNumber(in[i].second)); 651 | PyList_SetItem(M, i, pair); 652 | } 653 | return M; 654 | } 655 | 656 | template < typename Integer > 657 | static PyObject* 658 | NmzStanleyDataToPyList(const libnormaliz::STANLEYDATA< Integer >& StanleyData) 659 | { 660 | PyObject* pair = PyList_New(2); 661 | PyList_SetItem(pair, 0, 662 | NmzVectorToPyList< libnormaliz::key_t >(StanleyData.key)); 663 | PyList_SetItem(pair, 1, 664 | NmzMatrixToPyList(StanleyData.offsets.get_elements())); 665 | return pair; 666 | } 667 | 668 | template < typename Integer > 669 | static PyObject* NmzStanleyDecToPyList( 670 | const std::pair >, libnormaliz::Matrix > & StanleyDec) 671 | { 672 | const size_t n = StanleyDec.first.size(); 673 | PyObject* M = PyList_New(n); 674 | typename std::list< libnormaliz::STANLEYDATA< Integer > >::const_iterator S = 675 | StanleyDec.first.begin(); 676 | for (size_t i = 0; i < n; ++i) { 677 | PyList_SetItem(M, i, NmzStanleyDataToPyList(*S)); 678 | ++S; 679 | } 680 | PyObject* St=PyList_New(2); 681 | PyList_SetItem(St,0, M); 682 | PyList_SetItem(St, 1, NmzMatrixToPyList(StanleyDec.second.get_elements()) ); 683 | return St; 684 | } 685 | 686 | template < typename Integer > 687 | static PyObject* _NmzBasisChangeIntern(Cone< Integer >* C) 688 | { 689 | Sublattice_Representation< Integer > bc = C->getSublattice(); 690 | 691 | PyObject* res = PyList_New(3); 692 | PyList_SetItem(res, 0, NmzMatrixToPyList(bc.getEmbedding())); 693 | PyList_SetItem(res, 1, NmzMatrixToPyList(bc.getProjection())); 694 | PyList_SetItem(res, 2, NmzToPyNumber(bc.getAnnihilator())); 695 | // Dim, Rank, Equations and Congruences are already covered by special 696 | // functions ditto ExternalIndex 697 | return res; 698 | } 699 | 700 | static PyObject* 701 | NmzFacelatticeToPython(const map& lattice) 702 | { 703 | ssize_t len = lattice.size(); 704 | PyObject* list = PyList_New(len); 705 | ssize_t curr = 0; 706 | for (auto it = lattice.begin(); it != lattice.end(); it++) { 707 | PyObject* list_int = PyList_New(2); 708 | PyList_SetItem(list_int, 0, NmzToPyNumber(it->first)); 709 | PyList_SetItem(list_int, 1, NmzToPyNumber(it->second)); 710 | PyList_SetItem(list, curr, list_int); 711 | curr++; 712 | } 713 | return list; 714 | } 715 | 716 | static PyObject* 717 | NmzModularGradingsToPython(const vector >& gradings) 718 | { 719 | ssize_t nr_gradings = gradings.size(); 720 | PyObject* grad_list = PyList_New(nr_gradings); 721 | if(nr_gradings == 0) 722 | return grad_list; 723 | size_t curr = 0; 724 | for(auto& this_grad: gradings){ 725 | PyObject* list_part = PyList_New(this_grad.size()); 726 | size_t inner_curr = 0; 727 | for(auto& part: this_grad){ 728 | PyList_SetItem(list_part, inner_curr, NmzToPyNumber(part)); 729 | inner_curr++; 730 | } 731 | PyList_SetItem(grad_list, curr, list_part); 732 | curr++; 733 | } 734 | return grad_list; 735 | } 736 | 737 | template < typename Integer > 738 | static PyObject* 739 | NmzAutomorphismsToPython(const AutomorphismGroup< Integer >& grp) 740 | { 741 | int list_size = 6; 742 | if(grp.IsInput() || grp.IsAmbient()) 743 | list_size =7; 744 | 745 | PyObject* list = PyList_New(list_size); 746 | 747 | PyList_SetItem(list, 0, NmzToPyNumber(grp.getOrder())); 748 | PyList_SetItem(list, 1, BoolToPyBool(grp.IsIntegralityChecked())); 749 | PyList_SetItem(list, 2, BoolToPyBool(grp.IsIntegral())); 750 | 751 | if(grp.IsInput() || grp.IsAmbient()){ 752 | PyList_SetItem(list, 6, NmzMatrixToPyList(grp.getGens().get_elements())); 753 | PyObject* current = PyList_New(2); 754 | PyList_SetItem(current, 0, NmzMatrixToPyList(grp.getGensPerms())); 755 | PyList_SetItem(current, 1, NmzMatrixToPyList(grp.getGensOrbits())); 756 | PyList_SetItem(list, 3, current); 757 | 758 | current = PyList_New(2); 759 | vector > Empty; 760 | PyList_SetItem(current, 0, NmzMatrixToPyList(Empty)); 761 | PyList_SetItem(current, 1, NmzMatrixToPyList(Empty)); 762 | PyList_SetItem(list, 4, current); 763 | 764 | if(grp.IsAmbient()){ 765 | current = PyList_New(2); 766 | PyList_SetItem(current, 0, NmzMatrixToPyList(grp.getLinFormsPerms())); 767 | PyList_SetItem(current, 1, NmzMatrixToPyList(grp.getLinFormsOrbits())); 768 | PyList_SetItem(list, 5, current); 769 | } 770 | else{ 771 | vector > Empty; 772 | PyList_SetItem(current, 0, NmzMatrixToPyList(Empty)); 773 | PyList_SetItem(current, 1, NmzMatrixToPyList(Empty)); 774 | PyList_SetItem(list, 5, current); 775 | } 776 | } 777 | else{ 778 | PyObject* current = PyList_New(2); 779 | PyList_SetItem(current, 0, NmzMatrixToPyList(grp.getExtremeRaysPerms())); 780 | PyList_SetItem(current, 1, NmzMatrixToPyList(grp.getExtremeRaysOrbits())); 781 | PyList_SetItem(list, 3, current); 782 | 783 | current = PyList_New(2); 784 | PyList_SetItem(current, 0, NmzMatrixToPyList(grp.getVerticesPerms())); 785 | PyList_SetItem(current, 1, NmzMatrixToPyList(grp.getVerticesOrbits())); 786 | PyList_SetItem(list, 4, current); 787 | 788 | current = PyList_New(2); 789 | PyList_SetItem(current, 0, 790 | NmzMatrixToPyList(grp.getSupportHyperplanesPerms())); 791 | PyList_SetItem(current, 1, 792 | NmzMatrixToPyList(grp.getSupportHyperplanesOrbits())); 793 | PyList_SetItem(list, 5, current); 794 | } 795 | 796 | return list; 797 | } 798 | 799 | template < typename Integer > 800 | static PyObject* 801 | NmzFusionDataToPython(const vector > >& FusData) 802 | { 803 | int outer_list_size = FusData.size(); 804 | 805 | PyObject* outer_list = PyList_New(outer_list_size); 806 | 807 | for(int ring = 0; ring < outer_list_size; ring++){ 808 | int inner_list_size = FusData[ring].size(); 809 | PyObject* inner_list = PyList_New(inner_list_size); 810 | for(int mat = 0; mat < inner_list_size; mat++){ 811 | PyList_SetItem(inner_list, mat, NmzMatrixToPyList(FusData[ring][mat].get_elements())); 812 | } 813 | PyList_SetItem(outer_list, ring, inner_list); 814 | } 815 | return outer_list; 816 | } 817 | 818 | 819 | /*************************************************************************** 820 | * 821 | * PyCapsule handler functions 822 | * 823 | ***************************************************************************/ 824 | 825 | #ifdef ENFNORMALIZ 826 | struct NumberFieldCone { 827 | const renf_class* nf; 828 | Cone< renf_elem_class >* cone; 829 | }; 830 | #endif 831 | 832 | static void delete_cone_mpz(PyObject* cone) 833 | { 834 | Cone< mpz_class >* cone_ptr = reinterpret_cast< Cone< mpz_class >* >( 835 | PyCapsule_GetPointer(cone, cone_name)); 836 | delete cone_ptr; 837 | } 838 | 839 | static void delete_cone_long(PyObject* cone) 840 | { 841 | Cone< long long >* cone_ptr = reinterpret_cast< Cone< long long >* >( 842 | PyCapsule_GetPointer(cone, cone_name_long)); 843 | delete cone_ptr; 844 | } 845 | 846 | #ifdef ENFNORMALIZ 847 | static void delete_cone_renf(PyObject* cone) 848 | { 849 | NumberFieldCone* cone_ptr = reinterpret_cast< NumberFieldCone* >( 850 | PyCapsule_GetPointer(cone, cone_name_renf)); 851 | delete cone_ptr->cone; 852 | // delete cone_ptr->nf; 853 | } 854 | #endif 855 | 856 | static Cone< long long >* get_cone_long(PyObject* cone) 857 | { 858 | return reinterpret_cast< Cone< long long >* >( 859 | PyCapsule_GetPointer(cone, cone_name_long)); 860 | } 861 | 862 | static Cone< mpz_class >* get_cone_mpz(PyObject* cone) 863 | { 864 | return reinterpret_cast< Cone< mpz_class >* >( 865 | PyCapsule_GetPointer(cone, cone_name)); 866 | } 867 | 868 | #ifdef ENFNORMALIZ 869 | static Cone< renf_elem_class >* get_cone_renf(PyObject* cone) 870 | { 871 | NumberFieldCone* cone_ptr = reinterpret_cast< NumberFieldCone* >( 872 | PyCapsule_GetPointer(cone, cone_name_renf)); 873 | return cone_ptr->cone; 874 | } 875 | 876 | static const renf_class* get_cone_renf_renf(PyObject* cone) 877 | { 878 | NumberFieldCone* cone_ptr = reinterpret_cast< NumberFieldCone* >( 879 | PyCapsule_GetPointer(cone, cone_name_renf)); 880 | return cone_ptr->nf; 881 | } 882 | #endif 883 | 884 | static PyObject* pack_cone(Cone< mpz_class >* C, const void* dummy = nullptr) 885 | { 886 | return PyCapsule_New(reinterpret_cast< void* >(C), cone_name, 887 | &delete_cone_mpz); 888 | } 889 | 890 | static PyObject* pack_cone(Cone< long long >* C, const void* dummy = nullptr) 891 | { 892 | return PyCapsule_New(reinterpret_cast< void* >(C), cone_name_long, 893 | &delete_cone_long); 894 | } 895 | 896 | #ifdef ENFNORMALIZ 897 | static PyObject* pack_cone(Cone< renf_elem_class >* C, const void* nf) 898 | { 899 | NumberFieldCone* cone_ptr = new NumberFieldCone(); 900 | cone_ptr->nf = reinterpret_cast< const renf_class* >(nf); 901 | cone_ptr->cone = C; 902 | return PyCapsule_New(reinterpret_cast< void* >(cone_ptr), cone_name_renf, 903 | &delete_cone_renf); 904 | } 905 | #endif 906 | 907 | static bool is_cone(PyObject* cone) 908 | { 909 | if (PyCapsule_CheckExact(cone)) { 910 | const char *name = PyCapsule_GetName(cone); 911 | return !strcmp(name, cone_name) || !strcmp(name, cone_name_long) || 912 | !strcmp(name, cone_name_renf); 913 | } 914 | return false; 915 | } 916 | 917 | static bool is_cone_mpz(PyObject* cone) 918 | { 919 | if (PyCapsule_CheckExact(cone)) { 920 | const char *name = PyCapsule_GetName(cone); 921 | return !strcmp(name, cone_name); 922 | } 923 | return false; 924 | } 925 | 926 | static bool is_cone_long(PyObject* cone) 927 | { 928 | if (PyCapsule_CheckExact(cone)) { 929 | const char *name = PyCapsule_GetName(cone); 930 | return !strcmp(name, cone_name_long); 931 | } 932 | return false; 933 | } 934 | 935 | #ifdef ENFNORMALIZ 936 | static bool is_cone_renf(PyObject* cone) 937 | { 938 | if (PyCapsule_CheckExact(cone)) { 939 | const char *name = PyCapsule_GetName(cone); 940 | return !strcmp(name, cone_name_renf); 941 | } 942 | return false; 943 | } 944 | #endif 945 | 946 | /*************************************************************************** 947 | * 948 | * Cone property list 949 | * 950 | ***************************************************************************/ 951 | 952 | /* 953 | @Name NmzListConeProperties 954 | @Arguments none 955 | @Description 956 | Returns two lists of strings. 957 | The first list are all cone properties that define compute 958 | goals in Normaliz (see Normaliz manual for details) 959 | The second list are all cone properties that define internal 960 | control flow control in Normaliz, and which should not be used 961 | to get results of computations. 962 | All entries of the first list can be passed to NmzResult 963 | to get the result of a normaliz computation. 964 | All entries of the second list can be passed to NmzCompute 965 | to set different options for Normaliz computations. 966 | */ 967 | static PyObject* NmzListConeProperties(PyObject* args) 968 | { 969 | FUNC_BEGIN 970 | 971 | PyObject* return_list = PyList_New(2); 972 | 973 | ConeProperties goals = libnormaliz::all_goals(); 974 | ConeProperties options = libnormaliz::all_options(); 975 | 976 | int number_goals = goals.count(); 977 | int number_options = options.count(); 978 | 979 | PyObject* goal_list = PyList_New(number_goals); 980 | PyObject* option_list = PyList_New(number_options); 981 | 982 | PyList_SetItem(return_list, 0, goal_list); 983 | PyList_SetItem(return_list, 1, option_list); 984 | 985 | int list_position = 0; 986 | for (int i = 0; i < libnormaliz::ConeProperty::EnumSize; i++) { 987 | if (goals.test(static_cast< libnormaliz::ConeProperty::Enum >(i))) { 988 | string name = libnormaliz::toString( 989 | static_cast< libnormaliz::ConeProperty::Enum >(i)); 990 | PyList_SetItem(goal_list, list_position, StringToPyUnicode(name)); 991 | list_position++; 992 | } 993 | } 994 | 995 | list_position = 0; 996 | for (int i = 0; i < libnormaliz::ConeProperty::EnumSize; i++) { 997 | if (options.test(static_cast< libnormaliz::ConeProperty::Enum >(i))) { 998 | string name = libnormaliz::toString( 999 | static_cast< libnormaliz::ConeProperty::Enum >(i)); 1000 | PyList_SetItem(option_list, list_position, 1001 | StringToPyUnicode(name)); 1002 | list_position++; 1003 | } 1004 | } 1005 | 1006 | return return_list; 1007 | 1008 | FUNC_END 1009 | } 1010 | 1011 | /*************************************************************************** 1012 | * 1013 | * NmzCone 1014 | * 1015 | ***************************************************************************/ 1016 | 1017 | template < typename Integer > 1018 | static PyObject* _NmzConeIntern(PyObject* kwargs) 1019 | { 1020 | map< InputType, vector< vector< mpq_class > > > input; 1021 | 1022 | bool grading_polynomial = false; 1023 | string polynomial; 1024 | 1025 | if (kwargs != NULL) { 1026 | PyObject* keys = PyDict_Keys(kwargs); 1027 | PyObject* values = PyDict_Values(kwargs); 1028 | const int length = PySequence_Size(keys); 1029 | for (int i = 0; i < length; i++) { 1030 | string type_string = 1031 | PyUnicodeToString(PySequence_GetItem(keys, i)); 1032 | if (type_string == "CreateAsLongLong") { 1033 | continue; 1034 | } 1035 | PyObject* current_value = PySequence_GetItem(values, i); 1036 | if (current_value == Py_None) 1037 | continue; 1038 | if (type_string.compare("polynomial") == 0) { 1039 | polynomial = PyUnicodeToString(current_value); 1040 | grading_polynomial = true; 1041 | continue; 1042 | } 1043 | vector< vector< mpq_class > > Mat; 1044 | try { 1045 | PyInputToNmz(Mat, current_value); 1046 | } 1047 | catch (PyNormalizInputException& e) { 1048 | PyErr_SetString(PyNormaliz_cppError, 1049 | (string("When parsing ") + type_string + 1050 | ": " + e.what_message()) 1051 | .c_str()); 1052 | return NULL; 1053 | } 1054 | input[libnormaliz::to_type(type_string)] = Mat; 1055 | } 1056 | } 1057 | 1058 | Cone< Integer >* C = new Cone< Integer >(input); 1059 | 1060 | if (grading_polynomial) { 1061 | C->setPolynomial(polynomial); 1062 | } 1063 | 1064 | PyObject* return_container = pack_cone(C); 1065 | 1066 | return return_container; 1067 | } 1068 | 1069 | #ifdef ENFNORMALIZ 1070 | static PyObject* _NmzConeIntern_renf(PyObject* kwargs) 1071 | { 1072 | 1073 | FUNC_BEGIN 1074 | PyObject* number_field_data = 1075 | PyDict_GetItemString(kwargs, "number_field"); 1076 | if (number_field_data == NULL) { 1077 | PyErr_SetString(PyNormaliz_cppError, "no number field data given"); 1078 | return NULL; 1079 | } 1080 | if (!PySequence_Check(number_field_data)) { 1081 | PyErr_SetString(PyNormaliz_cppError, 1082 | "number field data must be a list"); 1083 | return NULL; 1084 | } 1085 | if (PySequence_Size(number_field_data) != 3) { 1086 | PyErr_SetString( 1087 | PyNormaliz_cppError, 1088 | "number field data must be a list with three entries"); 1089 | return NULL; 1090 | } 1091 | 1092 | // number_field_data contains 3 entries: poly, var, emb 1093 | // All are strings 1094 | string poly = PyUnicodeToString(PySequence_GetItem(number_field_data, 0)); 1095 | string var = PyUnicodeToString(PySequence_GetItem(number_field_data, 1)); 1096 | string emb = PyUnicodeToString(PySequence_GetItem(number_field_data, 2)); 1097 | // boost::intrusive_ptr* renf = new boost::intrusive_ptr; 1098 | boost::intrusive_ptr renf = renf_class::make(poly, var, emb); 1099 | const renf_class* my_renf = renf.get(); 1100 | 1101 | map< InputType, vector< vector< renf_elem_class > > > input; 1102 | 1103 | 1104 | /* Do not delete entry of kwargs dict, as it might not 1105 | be owned by the cone constructor */ 1106 | // PyDict_DelItemString(kwargs,"number_field"); 1107 | if (kwargs != NULL) { 1108 | PyObject* keys = PyDict_Keys(kwargs); 1109 | PyObject* values = PyDict_Values(kwargs); 1110 | const int length = PySequence_Size(keys); 1111 | for (int i = 0; i < length; i++) { 1112 | string type_string = 1113 | PyUnicodeToString(PySequence_GetItem(keys, i)); 1114 | if (type_string == "number_field") 1115 | continue; 1116 | PyObject* current_value = PySequence_GetItem(values, i); 1117 | if (current_value == Py_None) 1118 | continue; 1119 | vector< vector< renf_elem_class > > Mat; 1120 | try { 1121 | prepare_nf_input(Mat, current_value, my_renf); 1122 | } 1123 | catch (PyNormalizInputException& e) { 1124 | PyErr_SetString(PyNormaliz_cppError, 1125 | (string("When parsing ") + type_string + 1126 | ": " + e.what_message()) 1127 | .c_str()); 1128 | return NULL; 1129 | } 1130 | input[libnormaliz::to_type(type_string)] = Mat; 1131 | } 1132 | } 1133 | 1134 | Cone< renf_elem_class >* C = new Cone< renf_elem_class >(input); 1135 | C->setRenf(my_renf); 1136 | 1137 | PyObject* return_container = pack_cone(C, my_renf); 1138 | 1139 | return return_container; 1140 | FUNC_END 1141 | } 1142 | #endif 1143 | 1144 | static PyObject* _NmzConeFromFile(PyObject* kwargs) 1145 | { 1146 | 1147 | static const char* from_file = "file"; 1148 | PyObject* create_from_file = StringToPyUnicode(from_file); 1149 | PyObject* FileName = PyDict_GetItem(kwargs, create_from_file); 1150 | string project(PyUnicodeToString(FileName)); 1151 | 1152 | std::string name_in = project + ".in"; 1153 | const char* file_in = name_in.c_str(); 1154 | 1155 | #ifdef ENFNORMALIZ 1156 | std::ifstream in; 1157 | in.open(file_in, std::ifstream::in); 1158 | if (!in.is_open()) { 1159 | string message = "error: Failed to open file " + name_in; 1160 | throw libnormaliz::BadInputException(message); 1161 | } 1162 | bool number_field_in_input = false; 1163 | std::string poly, var, emb; 1164 | std::string test; 1165 | while(in.good()){ 1166 | in >> test; 1167 | if(test == "number_field"){ 1168 | number_field_in_input = true; 1169 | libnormaliz::read_number_field_strings(in, poly, var, emb); 1170 | break; 1171 | } 1172 | } 1173 | in.close(); 1174 | 1175 | if(number_field_in_input){ 1176 | boost::intrusive_ptr renf = renf_class::make(poly, var, emb); 1177 | const renf_class* my_renf = renf.get(); 1178 | Cone< renf_elem_class >* C = new Cone< renf_elem_class >(project); 1179 | PyObject* return_container = pack_cone(C, my_renf); 1180 | return return_container; 1181 | } 1182 | #endif 1183 | 1184 | static const char* string_for_long_long = "CreateAsLongLong"; 1185 | PyObject* create_as_long_long = StringToPyUnicode(string_for_long_long); 1186 | 1187 | if (PyDict_Contains(kwargs, create_as_long_long) == 1) { 1188 | Cone< long long >* C = new Cone< long long >(project); 1189 | PyObject* return_container = pack_cone(C); 1190 | return return_container; 1191 | } 1192 | else{ 1193 | Cone< mpz_class >* C = new Cone< mpz_class >(project); 1194 | PyObject* return_container = pack_cone(C); 1195 | return return_container; 1196 | } 1197 | } 1198 | 1199 | /* 1200 | @Name NmzCone 1201 | @Arguments 1202 | @Description 1203 | Constructs a normaliz cone object. The keywords must be 1204 | Normaliz input types, and the values for the keys matrices 1205 | (consisting of either Longs, Floats, or strings for rationals), 1206 | lists for single vector input types, or bools for boolean input type. 1207 | Special cases are a string describing a polynomial for the polynomial 1208 | input type, and the CreateAsLongLong keyword to restrict normaliz computations 1209 | to machine integers instead of arbitrary precision numbers. 1210 | */ 1211 | static PyObject* _NmzCone(PyObject* self, PyObject* args, PyObject* kwargs) 1212 | { 1213 | FUNC_BEGIN 1214 | static const char* from_file = "file"; 1215 | PyObject* create_from_file = StringToPyUnicode(from_file); 1216 | if (kwargs != NULL && PyDict_Contains(kwargs, create_from_file) == 1) { 1217 | return _NmzConeFromFile(kwargs); 1218 | } 1219 | 1220 | static const char* string_for_long = "CreateAsLongLong"; 1221 | PyObject* create_as_long_long = StringToPyUnicode(string_for_long); 1222 | #ifdef ENFNORMALIZ 1223 | static const char* string_for_renf = "number_field"; 1224 | PyObject* create_as_renf = StringToPyUnicode(string_for_renf); 1225 | #endif 1226 | 1227 | if (kwargs != NULL && PyDict_Contains(kwargs, create_as_long_long) == 1) { 1228 | create_as_long_long = PyDict_GetItem(kwargs, create_as_long_long); 1229 | if (create_as_long_long == Py_True) { 1230 | return _NmzConeIntern< long long >(kwargs); 1231 | } 1232 | } 1233 | #ifdef ENFNORMALIZ 1234 | else if (kwargs != NULL && PyDict_Contains(kwargs, create_as_renf) == 1) { 1235 | return _NmzConeIntern_renf(kwargs); 1236 | } 1237 | #endif 1238 | return _NmzConeIntern< mpz_class >(kwargs); 1239 | FUNC_END 1240 | } 1241 | 1242 | /* 1243 | @Name NmzConeCopy 1244 | @Arguments Cone 1245 | @Description 1246 | Returns a copy of the cone. 1247 | */ 1248 | static PyObject* _NmzConeCopy(PyObject* self, PyObject* args) 1249 | { 1250 | FUNC_BEGIN 1251 | PyObject* cone = PyTuple_GetItem(args, 0); 1252 | if (!is_cone(cone)) { 1253 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 1254 | return NULL; 1255 | } 1256 | 1257 | if (is_cone_mpz(cone)) { 1258 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 1259 | Cone< mpz_class >* new_cone = new Cone< mpz_class >(*cone_ptr); 1260 | return pack_cone(new_cone); 1261 | } 1262 | else if (is_cone_long(cone)) { 1263 | Cone< long long >* cone_ptr = get_cone_long(cone); 1264 | Cone< long long >* new_cone = new Cone< long long >(*cone_ptr); 1265 | return pack_cone(new_cone); 1266 | } 1267 | #ifdef ENFNORMALIZ 1268 | else if (is_cone_renf(cone)) { 1269 | Cone< renf_elem_class >* cone_ptr = get_cone_renf(cone); 1270 | Cone< renf_elem_class >* new_cone = 1271 | new Cone< renf_elem_class >(*cone_ptr); 1272 | return pack_cone(new_cone, get_cone_renf_renf(cone)); 1273 | } 1274 | #endif 1275 | Py_RETURN_NONE; 1276 | FUNC_END 1277 | } 1278 | 1279 | /*************************************************************************** 1280 | * 1281 | * NmzHilbertSeries 1282 | * 1283 | ***************************************************************************/ 1284 | 1285 | /* SUPERFLUOUS 1286 | template < typename Integer > 1287 | static PyObject* NmzHilbertSeries(Cone< Integer >* C, PyObject* args) 1288 | { 1289 | FUNC_BEGIN 1290 | 1291 | const int arg_len = PyTuple_Size(args); 1292 | 1293 | if (arg_len == 1) { 1294 | bool is_HSOP = C->isComputed(libnormaliz::ConeProperty::HSOP); 1295 | return NmzHilbertSeriesToPyList(C->getHilbertSeries(), is_HSOP); 1296 | } 1297 | 1298 | PyObject* is_HSOP = PyTuple_GetItem(args, 1); 1299 | 1300 | if (is_HSOP == Py_True) { 1301 | if (!C->isComputed(libnormaliz::ConeProperty::HSOP)) 1302 | C->compute(libnormaliz::ConeProperty::HSOP); 1303 | return NmzHilbertSeriesToPyList(C->getHilbertSeries(), true); 1304 | } 1305 | else { 1306 | return NmzHilbertSeriesToPyList(C->getHilbertSeries(), false); 1307 | } 1308 | FUNC_END 1309 | } 1310 | 1311 | 1312 | static PyObject* NmzHilbertSeries_Outer(PyObject* self, PyObject* args) 1313 | { 1314 | 1315 | FUNC_BEGIN 1316 | 1317 | PyObject* cone = PyTuple_GetItem(args, 0); 1318 | 1319 | if (!is_cone(cone)) { 1320 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 1321 | return NULL; 1322 | } 1323 | 1324 | TempSignalHandler tmpHandler; // use custom signal handler 1325 | 1326 | if (is_cone_mpz(cone)) { 1327 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 1328 | return NmzHilbertSeries(cone_ptr, args); 1329 | } 1330 | else if (is_cone_long(cone)) { 1331 | Cone< long long >* cone_ptr = get_cone_long(cone); 1332 | return NmzHilbertSeries(cone_ptr, args); 1333 | } 1334 | else { 1335 | PyErr_SetString(PyNormaliz_cppError, 1336 | "Hilbert series not available for renf cone"); 1337 | return NULL; 1338 | } 1339 | FUNC_END 1340 | } 1341 | */ 1342 | 1343 | /*************************************************************************** 1344 | * 1345 | * NmzCompute 1346 | * 1347 | ***************************************************************************/ 1348 | 1349 | 1350 | template < typename Integer > 1351 | static PyObject* _NmzCompute(Cone< Integer >* C, PyObject* args) 1352 | { 1353 | FUNC_BEGIN 1354 | 1355 | const int arg_len = PyTuple_Size(args); 1356 | 1357 | PyObject* to_compute; 1358 | 1359 | if (arg_len == 2) { 1360 | PyObject* first_arg = PyTuple_GetItem(args, 1); 1361 | if (PyList_Check(first_arg) || PyTuple_Check(first_arg)) { 1362 | to_compute = first_arg; 1363 | Py_IncRef(to_compute); 1364 | } 1365 | else { 1366 | to_compute = PyList_New(1); 1367 | int result = PyList_SetItem(to_compute, 0, first_arg); 1368 | if (result != 0) { 1369 | PyErr_SetString(PyNormaliz_cppError, 1370 | "List could not be created"); 1371 | Py_DecRef(to_compute); 1372 | return NULL; 1373 | } 1374 | } 1375 | } 1376 | else { 1377 | to_compute = PyList_New(arg_len - 1); 1378 | for (int i = 1; i < arg_len; i++) { 1379 | PyList_SetItem(to_compute, i-1, PyTuple_GetItem(args, i)); 1380 | } 1381 | } 1382 | 1383 | ConeProperties propsToCompute; 1384 | const int n = PySequence_Size(to_compute); 1385 | 1386 | for (int i = 0; i < n; ++i) { 1387 | PyObject* prop = PySequence_GetItem(to_compute, i); 1388 | if (!string_check(prop)) { 1389 | PyErr_SetString(PyNormaliz_cppError, 1390 | "All elements must be strings"); 1391 | Py_DecRef(to_compute); 1392 | return NULL; 1393 | } 1394 | string prop_str(PyUnicodeToString(prop)); 1395 | propsToCompute.set(libnormaliz::toConeProperty(prop_str)); 1396 | } 1397 | 1398 | ConeProperties notComputed = C->compute(propsToCompute); 1399 | 1400 | // Cone.compute returns the not computed properties 1401 | // we return a bool, true when everything requested was computed 1402 | Py_DecRef(to_compute); 1403 | return BoolToPyBool(notComputed.goals().none()); 1404 | FUNC_END 1405 | } 1406 | 1407 | 1408 | static PyObject* _NmzCompute_Outer(PyObject* self, PyObject* args) 1409 | { 1410 | 1411 | FUNC_BEGIN 1412 | 1413 | PyObject* cone = PyTuple_GetItem(args, 0); 1414 | 1415 | PyObject* result = NULL; 1416 | 1417 | if (!is_cone(cone)) { 1418 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 1419 | return NULL; 1420 | } 1421 | 1422 | TempSignalHandler tmpHandler; // use custom signal handler 1423 | 1424 | if (is_cone_mpz(cone)) { 1425 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 1426 | result = _NmzCompute(cone_ptr, args); 1427 | } 1428 | else if (is_cone_long(cone)) { 1429 | Cone< long long >* cone_ptr = get_cone_long(cone); 1430 | result = _NmzCompute(cone_ptr, args); 1431 | } 1432 | #ifdef ENFNORMALIZ 1433 | else if (is_cone_renf(cone)) { 1434 | Cone< renf_elem_class >* cone_ptr = get_cone_renf(cone); 1435 | result = _NmzCompute(cone_ptr, args); 1436 | } 1437 | #endif 1438 | 1439 | return result; 1440 | 1441 | FUNC_END 1442 | } 1443 | 1444 | /*************************************************************************** 1445 | * 1446 | * NmzModify 1447 | * 1448 | ***************************************************************************/ 1449 | 1450 | template 1451 | PyObject* _NmzModify(Cone* cone, PyObject* args) 1452 | { 1453 | string property = PyUnicodeToString( PyTuple_GetItem(args, 1) ); 1454 | PyObject* matrix_py = PyTuple_GetItem(args,2); 1455 | 1456 | vector> mat; 1457 | PyInputToNmz( mat,matrix_py ); 1458 | 1459 | cone->modifyCone(libnormaliz::to_type(property),mat); 1460 | Py_RETURN_TRUE; 1461 | 1462 | } 1463 | 1464 | #ifdef ENFNORMALIZ 1465 | PyObject* _NmzModify_Renf(Cone* cone, const renf_class* nf, PyObject* args) 1466 | { 1467 | string property = PyUnicodeToString( PyTuple_GetItem(args, 1) ); 1468 | PyObject* matrix_py = PyTuple_GetItem(args,2); 1469 | 1470 | vector> mat; 1471 | prepare_nf_input( mat,matrix_py,nf ); 1472 | 1473 | cone->modifyCone(libnormaliz::to_type(property),mat); 1474 | Py_RETURN_TRUE; 1475 | 1476 | } 1477 | #endif 1478 | 1479 | PyObject* _NmzModify_Outer(PyObject* self, PyObject* args) 1480 | { 1481 | 1482 | FUNC_BEGIN 1483 | 1484 | PyObject* cone = PyTuple_GetItem(args, 0); 1485 | 1486 | if (!is_cone(cone)) { 1487 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 1488 | return NULL; 1489 | } 1490 | 1491 | TempSignalHandler tmpHandler; // use custom signal handler 1492 | 1493 | if (is_cone_mpz(cone)) { 1494 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 1495 | return _NmzModify(cone_ptr, args); 1496 | } 1497 | else if (is_cone_long(cone)) { 1498 | Cone< long long >* cone_ptr = get_cone_long(cone); 1499 | return _NmzModify(cone_ptr, args); 1500 | } 1501 | #ifdef ENFNORMALIZ 1502 | else if (is_cone_renf(cone)) { 1503 | Cone< renf_elem_class >* cone_ptr = get_cone_renf(cone); 1504 | const renf_class* nf = get_cone_renf_renf(cone); 1505 | return _NmzModify_Renf(cone_ptr, nf, args); 1506 | } 1507 | #endif 1508 | 1509 | Py_RETURN_TRUE; 1510 | 1511 | FUNC_END 1512 | } 1513 | 1514 | /*************************************************************************** 1515 | * 1516 | * NmzIsComputed 1517 | * 1518 | ***************************************************************************/ 1519 | 1520 | /* 1521 | @Name NmzIsComputed 1522 | @Arguments , 1523 | @Desctiption 1524 | Returns if the cone property is computed in the cone . 1525 | */ 1526 | template < typename Integer > 1527 | static PyObject* NmzIsComputed(Cone< Integer >* C, PyObject* prop) 1528 | { 1529 | FUNC_BEGIN 1530 | 1531 | libnormaliz::ConeProperty::Enum p = 1532 | libnormaliz::toConeProperty(PyUnicodeToString(prop)); 1533 | 1534 | return BoolToPyBool(C->isComputed(p)); 1535 | 1536 | FUNC_END 1537 | } 1538 | 1539 | static PyObject* NmzIsComputed_Outer(PyObject* self, PyObject* args) 1540 | { 1541 | FUNC_BEGIN 1542 | 1543 | PyObject* cone = PyTuple_GetItem(args, 0); 1544 | PyObject* to_compute = PyTuple_GetItem(args, 1); 1545 | 1546 | if (!is_cone(cone)) { 1547 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 1548 | return NULL; 1549 | } 1550 | 1551 | if (is_cone_mpz(cone)) { 1552 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 1553 | return NmzIsComputed(cone_ptr, to_compute); 1554 | } 1555 | else if (is_cone_long(cone)) { 1556 | Cone< long long >* cone_ptr = get_cone_long(cone); 1557 | return NmzIsComputed(cone_ptr, to_compute); 1558 | } 1559 | #ifdef ENFNORMALIZ 1560 | else if (is_cone_renf(cone)) { 1561 | Cone< renf_elem_class >* cone_ptr = get_cone_renf(cone); 1562 | return NmzIsComputed(cone_ptr, to_compute); 1563 | } 1564 | #endif 1565 | Py_RETURN_FALSE; 1566 | 1567 | FUNC_END 1568 | } 1569 | 1570 | /*************************************************************************** 1571 | * 1572 | * NmzSetGrading 1573 | * 1574 | ***************************************************************************/ 1575 | 1576 | template < typename Integer > 1577 | static PyObject* NmzSetGrading_inner(Cone< Integer >* cone, PyObject* grad) 1578 | { 1579 | vector< Integer > grad_c; 1580 | bool result = PyListToNmz(grad_c, grad); 1581 | if (!result) { 1582 | PyErr_SetString(PyNormaliz_cppError, 1583 | "grading argument is not an integer list"); 1584 | return NULL; 1585 | } 1586 | cone->resetGrading(grad_c); 1587 | Py_RETURN_NONE; 1588 | } 1589 | 1590 | #ifdef ENFNORMALIZ 1591 | template <> 1592 | PyObject* NmzSetGrading_inner(Cone< renf_elem_class >* cone, PyObject* grad) 1593 | { 1594 | vector< renf_elem_class > grad_renf; 1595 | vector > grad_mat; // a cheap way to convert vectors 1596 | PyObject* PyHelpMat = PyList_New(1); // better: rebuild conversion to renf 1597 | PyList_SetItem(PyHelpMat, 0, grad); 1598 | prepare_nf_input(grad_mat, PyHelpMat,cone->getRenf()); 1599 | grad_renf = grad_mat[0]; 1600 | 1601 | cone->resetGrading(grad_renf); 1602 | Py_RETURN_NONE; 1603 | } 1604 | #endif 1605 | 1606 | static PyObject* NmzSetGrading(PyObject* self, PyObject* args) 1607 | { 1608 | FUNC_BEGIN 1609 | PyObject* cone = PyTuple_GetItem(args, 0); 1610 | PyObject* grading_py = PyTuple_GetItem(args, 1); 1611 | if (!is_cone(cone)) { 1612 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 1613 | return NULL; 1614 | } 1615 | if (is_cone_mpz(cone)) { 1616 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 1617 | return NmzSetGrading_inner(cone_ptr, grading_py); 1618 | } 1619 | if (is_cone_long(cone)) { 1620 | Cone< long long >* cone_ptr = get_cone_long(cone); 1621 | return NmzSetGrading_inner(cone_ptr, grading_py); 1622 | } 1623 | #ifdef ENFNORMALIZ 1624 | if (is_cone_renf(cone)) { 1625 | Cone< renf_elem_class >* cone_ptr = get_cone_renf(cone); 1626 | return NmzSetGrading_inner(cone_ptr, grading_py); 1627 | } 1628 | #endif 1629 | FUNC_END 1630 | 1631 | Py_RETURN_NONE; 1632 | } 1633 | 1634 | /*************************************************************************** 1635 | * 1636 | * NmzSetProjectionCoords 1637 | * 1638 | ***************************************************************************/ 1639 | 1640 | template < typename Integer > 1641 | static PyObject* NmzSetProjectionCoords_inner(Cone< Integer >* cone, PyObject* coords) 1642 | { 1643 | vector< Integer > coords_c; 1644 | bool result = PyListToNmz(coords_c, coords); 1645 | if (!result) { 1646 | PyErr_SetString(PyNormaliz_cppError, 1647 | " is not an integer list"); 1648 | return NULL; 1649 | } 1650 | for(size_t i=0; i< coords_c.size(); ++i){ 1651 | if(coords_c[i]!=0 && coords_c[i]!=1) 1652 | PyErr_SetString(PyNormaliz_cppError, "Projection coordinates must be 0 or 1"); 1653 | } 1654 | 1655 | cone->resetProjectionCoords(coords_c); 1656 | Py_RETURN_NONE; 1657 | } 1658 | 1659 | #ifdef ENFNORMALIZ 1660 | template <> 1661 | PyObject* NmzSetProjectionCoords_inner(Cone< renf_elem_class >* cone, PyObject* coords) 1662 | { 1663 | vector< renf_elem_class > coords_renf; 1664 | vector > coords_mat; // a cheap way to convert vectors 1665 | PyObject* PyHelpMat = PyList_New(1); // better: rebuild conversion to renf 1666 | PyList_SetItem(PyHelpMat, 0, coords); 1667 | prepare_nf_input(coords_mat, PyHelpMat,cone->getRenf()); 1668 | coords_renf = coords_mat[0]; 1669 | 1670 | cone->resetGrading(coords_renf); 1671 | Py_RETURN_NONE; 1672 | } 1673 | #endif 1674 | 1675 | 1676 | static PyObject* NmzSetProjectionCoords(PyObject* self, PyObject* args) 1677 | { 1678 | FUNC_BEGIN 1679 | PyObject* cone = PyTuple_GetItem(args, 0); 1680 | PyObject* coords_py = PyTuple_GetItem(args, 1); 1681 | if (!is_cone(cone)) { 1682 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 1683 | return NULL; 1684 | } 1685 | if (is_cone_long(cone)) { 1686 | Cone< long long >* cone_ptr = get_cone_long(cone); 1687 | return NmzSetProjectionCoords_inner(cone_ptr, coords_py); 1688 | } 1689 | if (is_cone_mpz(cone)) { 1690 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 1691 | return NmzSetProjectionCoords_inner(cone_ptr, coords_py); 1692 | } 1693 | #ifdef ENFNORMALIZ 1694 | if (is_cone_renf(cone)) { 1695 | Cone< renf_elem_class >* cone_ptr = get_cone_renf(cone); 1696 | return NmzSetProjectionCoords_inner(cone_ptr, coords_py); 1697 | } 1698 | #endif 1699 | FUNC_END 1700 | Py_RETURN_NONE; 1701 | } 1702 | 1703 | /*************************************************************************** 1704 | * 1705 | * NmzResult 1706 | * 1707 | ***************************************************************************/ 1708 | 1709 | /* 1710 | @Name NmzResult 1711 | @Arguments ,, 1712 | @Description 1713 | Returns the cone property belonging to the string of 1714 | cone . Please see the Normaliz manual for details on which cone 1715 | properties are available. Here are some special outputs that might differ from 1716 | Normaliz: 1717 | * HilbertSeries and WeightedEhrhartSeries 1718 | The returned object is a list with three entries: The first one describes 1719 | the numerator of the Hilbert series, the second one the denominator, and the 1720 | last one is the shift. If you pass the HSOP option, output will be done in 1721 | HSOP format. 1722 | * Grading 1723 | Returns a list with two entries. First is the grading, second one is the 1724 | grading denominator. 1725 | * Sublattice 1726 | Returns a list with three entries. First is the embedding of the sublattice, 1727 | second is the projection third is the annihilator. 1728 | * IntegerHull and ProjectCone return new cones. 1729 | * StanleyDec 1730 | Returns a list containing the Stanley decomposition. All entries are 1731 | 2-tuples. First entry in the tuple is the key, second the decomposition data. 1732 | */ 1733 | 1734 | template < typename Integer > 1735 | static PyObject* 1736 | _NmzResultImpl(Cone< Integer >* C, PyObject* prop_obj, const void* nf = nullptr) 1737 | { 1738 | 1739 | string prop = PyUnicodeToString(prop_obj); 1740 | 1741 | libnormaliz::ConeProperty::Enum p = libnormaliz::toConeProperty(prop); 1742 | 1743 | ConeProperties notComputed; 1744 | { 1745 | TempSignalHandler tmpHandler; // use custom signal handler 1746 | notComputed = C->compute(ConeProperties(p)); 1747 | } 1748 | 1749 | if (notComputed.goals().any()) { 1750 | Py_RETURN_NONE; 1751 | } 1752 | 1753 | // Handle standard cases 1754 | libnormaliz::OutputType::Enum outputtype = libnormaliz::output_type(p); 1755 | 1756 | switch (p) { 1757 | 1758 | case libnormaliz::ConeProperty::Triangulation:{ 1759 | return NmzTriangleListToPyList< Integer >(C->getTriangulation()); 1760 | } 1761 | 1762 | case libnormaliz::ConeProperty::ConeDecomposition:{ 1763 | return NmzTriangleListToPyList< Integer >(C->getConeDecomposition()); 1764 | } 1765 | 1766 | case libnormaliz::ConeProperty::AllGeneratorsTriangulation: 1767 | return NmzTriangleListToPyList< Integer >(C->getTriangulation( 1768 | libnormaliz::ConeProperty::AllGeneratorsTriangulation)); 1769 | 1770 | case libnormaliz::ConeProperty::LatticePointTriangulation: 1771 | return NmzTriangleListToPyList< Integer >(C->getTriangulation( 1772 | libnormaliz::ConeProperty::LatticePointTriangulation)); 1773 | 1774 | case libnormaliz::ConeProperty::UnimodularTriangulation: 1775 | return NmzTriangleListToPyList< Integer >(C->getTriangulation( 1776 | libnormaliz::ConeProperty::UnimodularTriangulation)); 1777 | 1778 | case libnormaliz::ConeProperty::HilbertSeries: { 1779 | bool is_HSOP = C->isComputed(libnormaliz::ConeProperty::HSOP); 1780 | return NmzHilbertSeriesToPyList(C->getHilbertSeries(), is_HSOP); 1781 | } 1782 | 1783 | case libnormaliz::ConeProperty::EhrhartSeries: { 1784 | bool is_HSOP = C->isComputed(libnormaliz::ConeProperty::HSOP); 1785 | return NmzHilbertSeriesToPyList(C->getEhrhartSeries(), is_HSOP); 1786 | } 1787 | 1788 | case libnormaliz::ConeProperty::WeightedEhrhartSeries: 1789 | return NmzWeightedEhrhartSeriesToPyList( C->getWeightedEhrhartSeries()); 1790 | 1791 | // though Grading has the return type vector we make it 1792 | // a complex structure within PyNormaliz since we want to combine it 1793 | // with the grading denominator 1794 | case libnormaliz::ConeProperty::Grading: { 1795 | vector< Integer > grad = C->getGrading(); 1796 | Integer denom = C->getGradingDenom(); 1797 | PyObject* return_list = PyList_New(2); 1798 | PyList_SetItem(return_list, 0, NmzVectorToPyList(grad)); 1799 | PyList_SetItem(return_list, 1, NmzToPyNumber(denom)); 1800 | return return_list; 1801 | } 1802 | 1803 | case libnormaliz::ConeProperty::StanleyDec: 1804 | return NmzStanleyDecToPyList(C->getStanleyDec()); 1805 | 1806 | case libnormaliz::ConeProperty::InclusionExclusionData: 1807 | return NmzPairVectorToPyList< long >( 1808 | C->getInclusionExclusionData()); 1809 | 1810 | /* returned as a matrix, no need to make it a complex property 1811 | case libnormaliz::ConeProperty::Equations: 1812 | return NmzMatrixToPyList(C->getSublattice().getEquations()); 1813 | 1814 | case libnormaliz::ConeProperty::Congruences: 1815 | return NmzMatrixToPyList(C->getSublattice().getCongruences()); 1816 | */ 1817 | 1818 | case libnormaliz::ConeProperty::Sublattice: 1819 | return _NmzBasisChangeIntern(C); 1820 | 1821 | case libnormaliz::ConeProperty::ExternalIndex: 1822 | return NmzToPyNumber(C->getSublattice().getExternalIndex()); 1823 | 1824 | case libnormaliz::ConeProperty::IntegerHull: { 1825 | Cone< Integer >* hull = 1826 | new Cone< Integer >(C->getIntegerHullCone()); 1827 | return pack_cone(hull, nf); 1828 | } 1829 | 1830 | case libnormaliz::ConeProperty::ProjectCone: { 1831 | Cone< Integer >* projection = 1832 | new Cone< Integer >(C->getProjectCone()); 1833 | return pack_cone(projection, nf); 1834 | } 1835 | 1836 | case libnormaliz::ConeProperty::HilbertQuasiPolynomial: 1837 | return NmzHilbertQuasiPolynomialToPyList< mpz_class >( 1838 | C->getHilbertSeries()); 1839 | 1840 | case libnormaliz::ConeProperty::EhrhartQuasiPolynomial: 1841 | return NmzHilbertQuasiPolynomialToPyList< mpz_class >( 1842 | C->getEhrhartSeries()); 1843 | 1844 | case libnormaliz::ConeProperty::WeightedEhrhartQuasiPolynomial: 1845 | return NmzWeightedEhrhartQuasiPolynomialToPyList< mpz_class >( 1846 | C->getIntData()); 1847 | 1848 | case libnormaliz::ConeProperty::ClassGroup: 1849 | return NmzVectorToPyList(C->getClassGroup()); 1850 | 1851 | case libnormaliz::ConeProperty::FVector: 1852 | return NmzVectorToPyList(C->getFVector()); 1853 | 1854 | case libnormaliz::ConeProperty::FVectorOrbits: 1855 | return NmzVectorToPyList(C->getFVectorOrbits()); 1856 | 1857 | case libnormaliz::ConeProperty::DualFVector: 1858 | return NmzVectorToPyList(C->getDualFVector()); 1859 | 1860 | case libnormaliz::ConeProperty::DualFVectorOrbits: 1861 | return NmzVectorToPyList(C->getDualFVectorOrbits()); 1862 | 1863 | case libnormaliz::ConeProperty::FaceLattice: 1864 | return NmzFacelatticeToPython(C->getFaceLattice()); 1865 | 1866 | case libnormaliz::ConeProperty::FaceLatticeOrbits: 1867 | return NmzFacelatticeToPython(C->getFaceLatticeOrbits()); 1868 | 1869 | case libnormaliz::ConeProperty::DualFaceLattice: 1870 | return NmzFacelatticeToPython(C->getDualFaceLattice()); 1871 | 1872 | case libnormaliz::ConeProperty::DualFaceLatticeOrbits: 1873 | return NmzFacelatticeToPython(C->getDualFaceLatticeOrbits()); 1874 | 1875 | case libnormaliz::ConeProperty::Automorphisms: 1876 | return NmzAutomorphismsToPython(C->getAutomorphismGroup( 1877 | libnormaliz::ConeProperty::Automorphisms)); 1878 | 1879 | case libnormaliz::ConeProperty::AmbientAutomorphisms: 1880 | return NmzAutomorphismsToPython(C->getAutomorphismGroup( 1881 | libnormaliz::ConeProperty::AmbientAutomorphisms)); 1882 | 1883 | case libnormaliz::ConeProperty::InputAutomorphisms: 1884 | return NmzAutomorphismsToPython(C->getAutomorphismGroup( 1885 | libnormaliz::ConeProperty::InputAutomorphisms)); 1886 | 1887 | case libnormaliz::ConeProperty::CombinatorialAutomorphisms: 1888 | return NmzAutomorphismsToPython(C->getAutomorphismGroup( 1889 | libnormaliz::ConeProperty::CombinatorialAutomorphisms)); 1890 | 1891 | case libnormaliz::ConeProperty::RationalAutomorphisms: 1892 | return NmzAutomorphismsToPython(C->getAutomorphismGroup( 1893 | libnormaliz::ConeProperty::RationalAutomorphisms)); 1894 | 1895 | case libnormaliz::ConeProperty::EuclideanAutomorphisms: 1896 | return NmzAutomorphismsToPython(C->getAutomorphismGroup( 1897 | libnormaliz::ConeProperty::EuclideanAutomorphisms)); 1898 | 1899 | case libnormaliz::ConeProperty::FusionData: 1900 | return NmzFusionDataToPython(C->getFusionDataMatrix()); 1901 | 1902 | case libnormaliz::ConeProperty::InductionMatrices: 1903 | return NmzFusionDataToPython(C->getInductionMatrices()); 1904 | 1905 | case libnormaliz::ConeProperty::Incidence: 1906 | return NmzVectorToPyList(C->getIncidence()); 1907 | 1908 | case libnormaliz::ConeProperty::ModularGradings: 1909 | return NmzModularGradingsToPython(C->getModularGradings()); 1910 | 1911 | default: { 1912 | switch (outputtype) { 1913 | case libnormaliz::OutputType::Matrix: 1914 | return NmzMatrixToPyList(C->getMatrixConeProperty(p)); 1915 | case libnormaliz::OutputType::MatrixFloat: 1916 | return NmzMatrixToPyList( 1917 | C->getFloatMatrixConeProperty(p)); 1918 | case libnormaliz::OutputType::Vector: 1919 | return NmzVectorToPyList(C->getVectorConeProperty(p)); 1920 | case libnormaliz::OutputType::Integer: 1921 | return NmzToPyNumber(C->getIntegerConeProperty(p)); 1922 | case libnormaliz::OutputType::GMPInteger: 1923 | return NmzToPyNumber(C->getGMPIntegerConeProperty(p)); 1924 | case libnormaliz::OutputType::Rational: 1925 | return NmzToPyNumber(C->getRationalConeProperty(p)); 1926 | case libnormaliz::OutputType::FieldElem: 1927 | return NmzToPyNumber(C->getFieldElemConeProperty(p)); 1928 | case libnormaliz::OutputType::Float: 1929 | return NmzToPyNumber(C->getFloatConeProperty(p)); 1930 | case libnormaliz::OutputType::MachineInteger: 1931 | return NmzToPyNumber(C->getMachineIntegerConeProperty(p)); 1932 | case libnormaliz::OutputType::Bool: 1933 | return BoolToPyBool(C->getBooleanConeProperty(p)); 1934 | case libnormaliz::OutputType::Void: { 1935 | PyErr_SetString(PyNormaliz_cppError, 1936 | "ConeProperty is input-only"); 1937 | return NULL; 1938 | } 1939 | case libnormaliz::OutputType::Complex: { 1940 | PyErr_SetString(PyNormaliz_cppError, 1941 | "This should never happen"); 1942 | return NULL; 1943 | } 1944 | } 1945 | } 1946 | } 1947 | Py_RETURN_NONE; 1948 | } 1949 | 1950 | static PyObject* _NmzResult(PyObject* self, PyObject* args, PyObject* kwargs) 1951 | { 1952 | 1953 | FUNC_BEGIN 1954 | 1955 | RationalHandler = NULL; 1956 | FloatHandler = NULL; 1957 | 1958 | #ifdef ENFNORMALIZ 1959 | NumberfieldElementHandler = NULL; 1960 | #endif 1961 | 1962 | VectorHandler = NULL; 1963 | MatrixHandler = NULL; 1964 | 1965 | if(PyTuple_Size(args)!=2){ 1966 | PyErr_SetString(PyNormaliz_cppError, "Exactly one computation goal required for NmzResult"); 1967 | return NULL; 1968 | } 1969 | 1970 | PyObject* cone = PyTuple_GetItem(args, 0); 1971 | PyObject* prop = PyTuple_GetItem(args, 1); 1972 | 1973 | if (!is_cone(cone)) { 1974 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 1975 | return NULL; 1976 | } 1977 | 1978 | if (!string_check(prop)) { 1979 | PyErr_SetString(PyNormaliz_cppError, 1980 | "Second argument must be a unicode string"); 1981 | return NULL; 1982 | } 1983 | 1984 | if (kwargs) { 1985 | RationalHandler = PyDict_GetItemString(kwargs, "RationalHandler"); 1986 | FloatHandler = PyDict_GetItemString(kwargs, "FloatHandler"); 1987 | #ifdef ENFNORMALIZ 1988 | NumberfieldElementHandler = 1989 | PyDict_GetItemString(kwargs, "NumberfieldElementHandler"); 1990 | #endif 1991 | VectorHandler = PyDict_GetItemString(kwargs, "VectorHandler"); 1992 | MatrixHandler = PyDict_GetItemString(kwargs, "MatrixHandler"); 1993 | } 1994 | 1995 | PyObject* result = NULL; 1996 | 1997 | if (is_cone_mpz(cone)) { 1998 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 1999 | result = _NmzResultImpl(cone_ptr, prop); 2000 | } 2001 | else if (is_cone_long(cone)) { 2002 | Cone< long long >* cone_ptr = get_cone_long(cone); 2003 | result = _NmzResultImpl(cone_ptr, prop); 2004 | } 2005 | #ifdef ENFNORMALIZ 2006 | else if (is_cone_renf(cone)) { 2007 | Cone< renf_elem_class >* cone_ptr = get_cone_renf(cone); 2008 | result = _NmzResultImpl( 2009 | cone_ptr, prop, 2010 | reinterpret_cast< const void* >(get_cone_renf_renf(cone))); 2011 | } 2012 | #endif 2013 | 2014 | RationalHandler = NULL; 2015 | #ifdef ENFNORMALIZ 2016 | NumberfieldElementHandler = NULL; 2017 | #endif 2018 | VectorHandler = NULL; 2019 | MatrixHandler = NULL; 2020 | 2021 | return result; 2022 | 2023 | FUNC_END 2024 | } 2025 | 2026 | /*************************************************************************** 2027 | * 2028 | * Python verbosity 2029 | * 2030 | ***************************************************************************/ 2031 | 2032 | static PyObject* NmzSetVerboseDefault(PyObject* self, PyObject* args) 2033 | { 2034 | FUNC_BEGIN 2035 | PyObject* value = PyTuple_GetItem(args, 0); 2036 | if (value != Py_True && value != Py_False) { 2037 | PyErr_SetString(PyNormaliz_cppError, 2038 | "Argument must be True or False"); 2039 | return NULL; 2040 | } 2041 | return BoolToPyBool(libnormaliz::setVerboseDefault(value == Py_True)); 2042 | FUNC_END 2043 | } 2044 | 2045 | template < typename Integer > 2046 | static PyObject* NmzSetVerbose(Cone< Integer >* C, PyObject* value) 2047 | { 2048 | FUNC_BEGIN 2049 | return BoolToPyBool(C->setVerbose(value == Py_True)); 2050 | FUNC_END 2051 | } 2052 | 2053 | static PyObject* NmzSetVerbose_Outer(PyObject* self, PyObject* args) 2054 | { 2055 | FUNC_BEGIN 2056 | 2057 | PyObject* cone = PyTuple_GetItem(args, 0); 2058 | 2059 | if (!is_cone(cone)) { 2060 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2061 | return NULL; 2062 | } 2063 | 2064 | PyObject* value = PyTuple_GetItem(args, 1); 2065 | if (value != Py_True && value != Py_False) { 2066 | PyErr_SetString(PyNormaliz_cppError, 2067 | "Second argument must be True or False"); 2068 | return NULL; 2069 | } 2070 | 2071 | if (is_cone_mpz(cone)) { 2072 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2073 | return NmzSetVerbose(cone_ptr, value); 2074 | } 2075 | else if (is_cone_long(cone)) { 2076 | Cone< long long >* cone_ptr = get_cone_long(cone); 2077 | return NmzSetVerbose(cone_ptr, value); 2078 | } 2079 | #ifdef ENFNORMALIZ 2080 | else if (is_cone_renf(cone)) { 2081 | Cone< renf_elem_class >* cone_ptr = get_cone_renf(cone); 2082 | return NmzSetVerbose(cone_ptr, value); 2083 | } 2084 | #endif 2085 | Py_RETURN_NONE; 2086 | 2087 | FUNC_END 2088 | } 2089 | 2090 | /*************************************************************************** 2091 | * 2092 | * Get Polynomial 2093 | * 2094 | ***************************************************************************/ 2095 | 2096 | static PyObject* NmzGetPolynomial(PyObject* self, PyObject* args) 2097 | { 2098 | 2099 | FUNC_BEGIN 2100 | 2101 | PyObject* cone = PyTuple_GetItem(args, 0); 2102 | 2103 | if (!is_cone(cone)) { 2104 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2105 | return NULL; 2106 | } 2107 | 2108 | TempSignalHandler tmpHandler; // use custom signal handler 2109 | 2110 | if (is_cone_mpz(cone)) { 2111 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2112 | return StringToPyUnicode((cone_ptr->getIntData()).getPolynomial()); 2113 | } 2114 | else if (is_cone_long(cone)) { 2115 | Cone< long long >* cone_ptr = get_cone_long(cone); 2116 | return StringToPyUnicode((cone_ptr->getIntData()).getPolynomial()); 2117 | } 2118 | else { 2119 | PyErr_SetString(PyNormaliz_cppError, 2120 | "Polynomial not available for renf cone"); 2121 | return NULL; 2122 | } 2123 | 2124 | FUNC_END 2125 | } 2126 | 2127 | /*************************************************************************** 2128 | * 2129 | * NrCoeffQuasiPol 2130 | * 2131 | ***************************************************************************/ 2132 | 2133 | static PyObject* NmzSetNrCoeffQuasiPol(PyObject* self, PyObject* args) 2134 | { 2135 | 2136 | FUNC_BEGIN 2137 | 2138 | PyObject* cone = PyTuple_GetItem(args, 0); 2139 | 2140 | if (!is_cone(cone)) { 2141 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2142 | return NULL; 2143 | } 2144 | 2145 | PyObject* bound_py = PyTuple_GetItem(args, 1); 2146 | 2147 | TempSignalHandler tmpHandler; // use custom signal handler 2148 | 2149 | int overflow; 2150 | long bound = PyLong_AsLongLongAndOverflow(bound_py, &overflow); 2151 | if (is_cone_mpz(cone)) { 2152 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2153 | cone_ptr->setNrCoeffQuasiPol(bound); 2154 | Py_RETURN_TRUE; 2155 | } 2156 | else if (is_cone_long(cone)) { 2157 | Cone< long long >* cone_ptr = get_cone_long(cone); 2158 | cone_ptr->setNrCoeffQuasiPol(bound); 2159 | Py_RETURN_TRUE; 2160 | } 2161 | else { 2162 | PyErr_SetString(PyNormaliz_cppError, 2163 | "Cannot set quasi polynomial coeffs for renf cone"); 2164 | return NULL; 2165 | } 2166 | 2167 | FUNC_END 2168 | } 2169 | 2170 | /*************************************************************************** 2171 | * 2172 | * Polynomial 2173 | * 2174 | ***************************************************************************/ 2175 | 2176 | static PyObject* NmzSetPolynomial(PyObject* self, PyObject* args) 2177 | { 2178 | 2179 | FUNC_BEGIN 2180 | 2181 | PyObject* cone = PyTuple_GetItem(args, 0); 2182 | 2183 | if (!is_cone(cone)) { 2184 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2185 | return NULL; 2186 | } 2187 | 2188 | TempSignalHandler tmpHandler; // use custom signal handler 2189 | 2190 | PyObject* poly_pi = PyTuple_GetItem(args, 1); 2191 | 2192 | if(!string_check(poly_pi)){ 2193 | PyErr_SetString(PyNormaliz_cppError, "Polynomial must be given as a string"); 2194 | return NULL; 2195 | } 2196 | TempSignalHandler tmpHandler1; // use custom signal handler 2197 | 2198 | string polynomial = PyUnicodeToString(poly_pi); 2199 | 2200 | if (is_cone_mpz(cone)) { 2201 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2202 | cone_ptr->setPolynomial(polynomial); 2203 | Py_RETURN_TRUE; 2204 | } 2205 | else if (is_cone_long(cone)) { 2206 | Cone< long long >* cone_ptr = get_cone_long(cone); 2207 | cone_ptr->setPolynomial(polynomial); 2208 | Py_RETURN_TRUE; 2209 | } 2210 | else { 2211 | PyErr_SetString(PyNormaliz_cppError, 2212 | "Polynomial cannot be set for renf cone"); 2213 | return NULL; 2214 | } 2215 | 2216 | FUNC_END 2217 | } 2218 | 2219 | static PyObject* NmzSetPolynomialEquations(PyObject* self, PyObject* args) 2220 | { 2221 | 2222 | FUNC_BEGIN 2223 | 2224 | PyObject* cone = PyTuple_GetItem(args, 0); 2225 | 2226 | if (!is_cone(cone)) { 2227 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2228 | return NULL; 2229 | } 2230 | 2231 | TempSignalHandler tmpHandler; // use custom signal handler 2232 | 2233 | PyObject* polys_py = PyTuple_GetItem(args, 1); 2234 | if(!PyList_CheckExact(polys_py)) { 2235 | PyErr_SetString(PyNormaliz_cppError, "Second argument must be a list"); 2236 | return NULL; 2237 | } 2238 | 2239 | TempSignalHandler tmpHandler1; // use custom signal handler 2240 | 2241 | size_t nr_polys = PySequence_Size(polys_py); 2242 | vector PolyEquations; 2243 | for(size_t i = 0; i < nr_polys; ++i){ 2244 | if(!string_check(PyList_GetItem(polys_py,i))) { 2245 | PyErr_SetString(PyNormaliz_cppError, "Polynomial must be given as a string"); 2246 | return NULL; 2247 | } 2248 | string equ = PyUnicodeToString( PyList_GetItem(polys_py,i)); 2249 | PolyEquations.push_back(equ); 2250 | } 2251 | 2252 | if (is_cone_mpz(cone)) { 2253 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2254 | cone_ptr->setPolynomialEquations(PolyEquations); 2255 | Py_RETURN_TRUE; 2256 | } 2257 | if (is_cone_long(cone)) { 2258 | Cone< long long >* cone_ptr = get_cone_long(cone); 2259 | cone_ptr->setPolynomialEquations(PolyEquations); 2260 | Py_RETURN_TRUE; 2261 | } 2262 | #ifdef ENFNORMALIZ 2263 | Cone* cone_ptr = get_cone_renf(cone); 2264 | cone_ptr->setPolynomialEquations(PolyEquations); 2265 | Py_RETURN_TRUE; 2266 | #endif 2267 | 2268 | FUNC_END 2269 | } 2270 | 2271 | static PyObject* NmzSetPolynomialInequalities(PyObject* self, PyObject* args) 2272 | { 2273 | 2274 | FUNC_BEGIN 2275 | 2276 | PyObject* cone = PyTuple_GetItem(args, 0); 2277 | 2278 | if (!is_cone(cone)) { 2279 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2280 | return NULL; 2281 | } 2282 | 2283 | TempSignalHandler tmpHandler; // use custom signal handler 2284 | 2285 | PyObject* polys_py = PyTuple_GetItem(args, 1); 2286 | if(!PyList_CheckExact(polys_py)) { 2287 | PyErr_SetString(PyNormaliz_cppError, "Second argument must be a list"); 2288 | return NULL; 2289 | } 2290 | 2291 | TempSignalHandler tmpHandler1; // use custom signal handler 2292 | 2293 | size_t nr_polys = PySequence_Size(polys_py); 2294 | vector PolyInequalities; 2295 | for(size_t i = 0; i < nr_polys; ++i){ 2296 | if(!string_check(PyList_GetItem(polys_py,i))) { 2297 | PyErr_SetString(PyNormaliz_cppError, "Polynomial must be given as a string"); 2298 | return NULL; 2299 | } 2300 | string inequ = PyUnicodeToString( PyList_GetItem(polys_py,i)); 2301 | PolyInequalities.push_back(inequ); 2302 | } 2303 | 2304 | if (is_cone_mpz(cone)) { 2305 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2306 | cone_ptr->setPolynomialInequalities(PolyInequalities); 2307 | Py_RETURN_TRUE; 2308 | } 2309 | if (is_cone_long(cone)) { 2310 | Cone< long long >* cone_ptr = get_cone_long(cone); 2311 | cone_ptr->setPolynomialInequalities(PolyInequalities); 2312 | Py_RETURN_TRUE; 2313 | } 2314 | #ifdef ENFNORMALIZ 2315 | Cone* cone_ptr = get_cone_renf(cone); 2316 | cone_ptr->setPolynomialInequalities(PolyInequalities); 2317 | Py_RETURN_TRUE; 2318 | #endif 2319 | 2320 | FUNC_END 2321 | } 2322 | 2323 | /*************************************************************************** 2324 | * 2325 | * FaceCodimBound and other numerical parameters 2326 | * 2327 | ***************************************************************************/ 2328 | 2329 | static PyObject* NmzSetFaceCodimBound(PyObject* self, PyObject* args) 2330 | { 2331 | 2332 | FUNC_BEGIN 2333 | 2334 | PyObject* cone = PyTuple_GetItem(args, 0); 2335 | 2336 | if (!is_cone(cone)) { 2337 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2338 | return NULL; 2339 | } 2340 | 2341 | PyObject* bound_py = PyTuple_GetItem(args, 1); 2342 | 2343 | TempSignalHandler tmpHandler; // use custom signal handler 2344 | 2345 | int overflow; 2346 | long bound = PyLong_AsLongLongAndOverflow(bound_py, &overflow); 2347 | if (is_cone_mpz(cone)) { 2348 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2349 | cone_ptr->setFaceCodimBound(bound); 2350 | Py_RETURN_TRUE; 2351 | } 2352 | else if (is_cone_long(cone)) { 2353 | Cone< long long >* cone_ptr = get_cone_long(cone); 2354 | cone_ptr->setFaceCodimBound(bound); 2355 | Py_RETURN_TRUE; 2356 | } 2357 | #ifdef ENFNORMALIZ 2358 | else { 2359 | Cone* cone_ptr = get_cone_renf(cone); 2360 | cone_ptr->setFaceCodimBound(bound); 2361 | Py_RETURN_TRUE; 2362 | } 2363 | #endif 2364 | 2365 | FUNC_END 2366 | } 2367 | 2368 | static PyObject* NmzSetModularGrading(PyObject* self, PyObject* args) 2369 | { 2370 | 2371 | FUNC_BEGIN 2372 | 2373 | PyObject* cone = PyTuple_GetItem(args, 0); 2374 | 2375 | if (!is_cone(cone)) { 2376 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2377 | return NULL; 2378 | } 2379 | 2380 | PyObject* mod_gr_py = PyTuple_GetItem(args, 1); 2381 | 2382 | TempSignalHandler tmpHandler; // use custom signal handler 2383 | 2384 | int overflow; 2385 | long mod_gr = PyLong_AsLongLongAndOverflow(mod_gr_py, &overflow); 2386 | if (is_cone_mpz(cone)) { 2387 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2388 | cone_ptr->setModularGraing(mod_gr); 2389 | Py_RETURN_TRUE; 2390 | } 2391 | else if (is_cone_long(cone)) { 2392 | Cone< long long >* cone_ptr = get_cone_long(cone); 2393 | cone_ptr->setModularGraing(mod_gr); 2394 | Py_RETURN_TRUE; 2395 | } 2396 | #ifdef ENFNORMALIZ 2397 | else { 2398 | Cone* cone_ptr = get_cone_renf(cone); 2399 | cone_ptr->setModularGraing(mod_gr); 2400 | Py_RETURN_TRUE; 2401 | } 2402 | #endif 2403 | 2404 | FUNC_END 2405 | } 2406 | 2407 | static PyObject* NmzSetChosenFusionRing(PyObject* self, PyObject* args) 2408 | { 2409 | 2410 | FUNC_BEGIN 2411 | 2412 | PyObject* cone = PyTuple_GetItem(args, 0); 2413 | 2414 | if (!is_cone(cone)) { 2415 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2416 | return NULL; 2417 | } 2418 | 2419 | PyObject* chosen_ring_py = PyTuple_GetItem(args, 1); 2420 | 2421 | TempSignalHandler tmpHandler; // use custom signal handler 2422 | 2423 | int overflow; 2424 | long chosen_ring = PyLong_AsLongLongAndOverflow(chosen_ring_py, &overflow); 2425 | if (is_cone_mpz(cone)) { 2426 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2427 | cone_ptr->setChosenFusionRing(chosen_ring); 2428 | Py_RETURN_TRUE; 2429 | } 2430 | else if (is_cone_long(cone)) { 2431 | Cone< long long >* cone_ptr = get_cone_long(cone); 2432 | cone_ptr->setChosenFusionRing(chosen_ring); 2433 | Py_RETURN_TRUE; 2434 | } 2435 | #ifdef ENFNORMALIZ 2436 | else { 2437 | Cone* cone_ptr = get_cone_renf(cone); 2438 | cone_ptr->setChosenFusionRing(chosen_ring); 2439 | Py_RETURN_TRUE; 2440 | } 2441 | #endif 2442 | 2443 | FUNC_END 2444 | } 2445 | 2446 | static PyObject* NmzSetGBDegreeBound(PyObject* self, PyObject* args) 2447 | { 2448 | 2449 | FUNC_BEGIN 2450 | 2451 | PyObject* cone = PyTuple_GetItem(args, 0); 2452 | 2453 | if (!is_cone(cone)) { 2454 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2455 | return NULL; 2456 | } 2457 | 2458 | PyObject* bound_py = PyTuple_GetItem(args, 1); 2459 | 2460 | TempSignalHandler tmpHandler; // use custom signal handler 2461 | 2462 | int overflow; 2463 | long bound = PyLong_AsLongLongAndOverflow(bound_py, &overflow); 2464 | if (is_cone_mpz(cone)) { 2465 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2466 | cone_ptr->setGBDegreeBound(bound); 2467 | Py_RETURN_TRUE; 2468 | } 2469 | else if (is_cone_long(cone)) { 2470 | Cone< long long >* cone_ptr = get_cone_long(cone); 2471 | cone_ptr->setGBDegreeBound(bound); 2472 | Py_RETURN_TRUE; 2473 | } 2474 | #ifdef ENFNORMALIZ 2475 | else { 2476 | PyErr_SetString(PyNormaliz_cppError, "GB degree bound not defined for algebraic polyhedra"); 2477 | return NULL; 2478 | } 2479 | #endif 2480 | 2481 | FUNC_END 2482 | } 2483 | 2484 | static PyObject* NmzSetGBMinDegree(PyObject* self, PyObject* args) 2485 | { 2486 | 2487 | FUNC_BEGIN 2488 | 2489 | PyObject* cone = PyTuple_GetItem(args, 0); 2490 | 2491 | if (!is_cone(cone)) { 2492 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2493 | return NULL; 2494 | } 2495 | 2496 | PyObject* bound_py = PyTuple_GetItem(args, 1); 2497 | 2498 | TempSignalHandler tmpHandler; // use custom signal handler 2499 | 2500 | int overflow; 2501 | long bound = PyLong_AsLongLongAndOverflow(bound_py, &overflow); 2502 | if (is_cone_mpz(cone)) { 2503 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2504 | cone_ptr->setGBMinDegree(bound); 2505 | Py_RETURN_TRUE; 2506 | } 2507 | else if (is_cone_long(cone)) { 2508 | Cone< long long >* cone_ptr = get_cone_long(cone); 2509 | cone_ptr->setGBMinDegree(bound); 2510 | Py_RETURN_TRUE; 2511 | } 2512 | #ifdef ENFNORMALIZ 2513 | else { 2514 | PyErr_SetString(PyNormaliz_cppError, "GB min degree not defined for algebraic polyhedra"); 2515 | return NULL; 2516 | } 2517 | #endif 2518 | 2519 | FUNC_END 2520 | } 2521 | 2522 | static PyObject* NmzSetDecimalDigits(PyObject* self, PyObject* args) 2523 | { 2524 | 2525 | FUNC_BEGIN 2526 | 2527 | PyObject* cone = PyTuple_GetItem(args, 0); 2528 | 2529 | if (!is_cone(cone)) { 2530 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2531 | return NULL; 2532 | } 2533 | 2534 | PyObject* digits_py = PyTuple_GetItem(args, 1); 2535 | 2536 | TempSignalHandler tmpHandler; // use custom signal handler 2537 | 2538 | int overflow; 2539 | long digits = PyLong_AsLongLongAndOverflow(digits_py, &overflow); 2540 | if (is_cone_mpz(cone)) { 2541 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2542 | cone_ptr->setDecimalDigits(digits); 2543 | Py_RETURN_TRUE; 2544 | } 2545 | else if (is_cone_long(cone)) { 2546 | Cone< long long >* cone_ptr = get_cone_long(cone); 2547 | cone_ptr->setDecimalDigits(digits); 2548 | Py_RETURN_TRUE; 2549 | } 2550 | #ifdef ENFNORMALIZ 2551 | else { 2552 | Cone* cone_ptr = get_cone_renf(cone); 2553 | cone_ptr->setDecimalDigits(digits); 2554 | Py_RETURN_TRUE; 2555 | } 2556 | #endif 2557 | 2558 | FUNC_END 2559 | } 2560 | 2561 | /*************************************************************************** 2562 | * 2563 | * Get Symmetrized cone 2564 | * 2565 | ***************************************************************************/ 2566 | 2567 | static PyObject* NmzSymmetrizedCone(PyObject* self, PyObject* args) 2568 | { 2569 | 2570 | FUNC_BEGIN 2571 | 2572 | PyObject* cone = PyTuple_GetItem(args, 0); 2573 | 2574 | if (!is_cone(cone)) { 2575 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2576 | return NULL; 2577 | } 2578 | 2579 | TempSignalHandler tmpHandler; // use custom signal handler 2580 | 2581 | if (is_cone_mpz(cone)) { 2582 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2583 | Cone< mpz_class >& symm_cone = cone_ptr->getSymmetrizedCone(); 2584 | return pack_cone(new Cone< mpz_class >(symm_cone)); 2585 | } 2586 | else if (is_cone_long(cone)) { 2587 | Cone< long long >* cone_ptr = get_cone_long(cone); 2588 | Cone< long long >& symm_cone = cone_ptr->getSymmetrizedCone(); 2589 | return pack_cone(new Cone< long long >(symm_cone)); 2590 | } 2591 | else { 2592 | PyErr_SetString(PyNormaliz_cppError, 2593 | "Symmetrized cone not available for renf cone"); 2594 | return NULL; 2595 | } 2596 | 2597 | FUNC_END 2598 | } 2599 | 2600 | /*************************************************************************** 2601 | * 2602 | * Get expanded Hilbert series 2603 | * 2604 | ***************************************************************************/ 2605 | 2606 | static PyObject* NmzGetHilbertSeriesExpansion(PyObject* self, PyObject* args) 2607 | { 2608 | 2609 | FUNC_BEGIN 2610 | 2611 | PyObject* cone = PyTuple_GetItem(args, 0); 2612 | PyObject* py_degree = PyTuple_GetItem(args, 1); 2613 | 2614 | if (!is_cone(cone)) { 2615 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2616 | return NULL; 2617 | } 2618 | 2619 | if (!PyLong_Check(py_degree)) { 2620 | PyErr_SetString(PyNormaliz_cppError, 2621 | "Second argument must be a long"); 2622 | return NULL; 2623 | } 2624 | 2625 | long degree = PyLong_AsLong(py_degree); 2626 | libnormaliz::HilbertSeries HS; 2627 | TempSignalHandler tmpHandler; // use custom signal handler 2628 | 2629 | if (is_cone_mpz(cone)) { 2630 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2631 | HS = cone_ptr->getHilbertSeries(); 2632 | } 2633 | else if (is_cone_long(cone)) { 2634 | Cone< long long >* cone_ptr = get_cone_long(cone); 2635 | HS = cone_ptr->getHilbertSeries(); 2636 | } 2637 | else { 2638 | PyErr_SetString( 2639 | PyNormaliz_cppError, 2640 | "Hilbert series expansion not available for renf cone"); 2641 | return NULL; 2642 | } 2643 | 2644 | HS.set_expansion_degree(degree); 2645 | return NmzVectorToPyList(HS.getExpansion()); 2646 | 2647 | FUNC_END 2648 | } 2649 | 2650 | 2651 | static PyObject* NmzGetWeightedEhrhartSeriesExpansion(PyObject* self, PyObject* args) 2652 | { 2653 | 2654 | FUNC_BEGIN 2655 | 2656 | PyObject* cone = PyTuple_GetItem(args, 0); 2657 | PyObject* py_degree = PyTuple_GetItem(args, 1); 2658 | 2659 | if (!is_cone(cone)) { 2660 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2661 | return NULL; 2662 | } 2663 | 2664 | if (!PyLong_Check(py_degree)) { 2665 | PyErr_SetString(PyNormaliz_cppError, 2666 | "Second argument must be a long"); 2667 | return NULL; 2668 | } 2669 | 2670 | long degree = PyLong_AsLong(py_degree); 2671 | pair< libnormaliz::HilbertSeries, mpz_class > ES; 2672 | TempSignalHandler tmpHandler; // use custom signal handler 2673 | 2674 | if (is_cone_mpz(cone)) { 2675 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2676 | ES = cone_ptr->getWeightedEhrhartSeries(); 2677 | } 2678 | else if (is_cone_long(cone)) { 2679 | Cone< long long >* cone_ptr = get_cone_long(cone); 2680 | ES = cone_ptr->getWeightedEhrhartSeries(); 2681 | } 2682 | else { 2683 | PyErr_SetString( 2684 | PyNormaliz_cppError, 2685 | "Ehrhart series expansion not available for renf cone"); 2686 | return NULL; 2687 | } 2688 | 2689 | ES.first.set_expansion_degree(degree); 2690 | 2691 | PyObject* return_list = PyList_New(2); 2692 | PyList_SetItem(return_list, 0, NmzVectorToPyList(ES.first.getExpansion())); 2693 | PyList_SetItem(return_list, 1, NmzToPyNumber(ES.second)); 2694 | return return_list; 2695 | 2696 | FUNC_END 2697 | } 2698 | 2699 | static PyObject* NmzGetEhrhartSeriesExpansion(PyObject* self, PyObject* args) 2700 | { 2701 | 2702 | FUNC_BEGIN 2703 | 2704 | PyObject* cone = PyTuple_GetItem(args, 0); 2705 | PyObject* py_degree = PyTuple_GetItem(args, 1); 2706 | 2707 | if (!is_cone(cone)) { 2708 | PyErr_SetString(PyNormaliz_cppError, "First argument must be a cone"); 2709 | return NULL; 2710 | } 2711 | 2712 | if (!PyLong_Check(py_degree)) { 2713 | PyErr_SetString(PyNormaliz_cppError, 2714 | "Second argument must be a long"); 2715 | return NULL; 2716 | } 2717 | 2718 | long degree = PyLong_AsLong(py_degree); 2719 | libnormaliz::HilbertSeries ES; 2720 | TempSignalHandler tmpHandler; // use custom signal handler 2721 | 2722 | if (is_cone_mpz(cone)) { 2723 | Cone< mpz_class >* cone_ptr = get_cone_mpz(cone); 2724 | ES = cone_ptr->getEhrhartSeries(); 2725 | } 2726 | else if (is_cone_long(cone)) { 2727 | Cone< long long >* cone_ptr = get_cone_long(cone); 2728 | ES = cone_ptr->getEhrhartSeries(); 2729 | } 2730 | else { 2731 | PyErr_SetString( 2732 | PyNormaliz_cppError, 2733 | "Ehrhart series expansion not available for renf cone"); 2734 | return NULL; 2735 | } 2736 | 2737 | ES.set_expansion_degree(degree); 2738 | return NmzVectorToPyList(ES.getExpansion()); 2739 | 2740 | FUNC_END 2741 | } 2742 | 2743 | /*************************************************************************** 2744 | * 2745 | * Set number of threads 2746 | * 2747 | ***************************************************************************/ 2748 | 2749 | static PyObject* NmzSetNumberOfNormalizThreads(PyObject* self, PyObject* args) 2750 | { 2751 | 2752 | FUNC_BEGIN 2753 | 2754 | PyObject* num_threads = PyTuple_GetItem(args, 0); 2755 | 2756 | long num_threads_long; 2757 | 2758 | if (PyLong_Check(num_threads)) { 2759 | num_threads_long = PyLong_AsLong(num_threads); 2760 | } 2761 | #if PY_MAJOR_VERSION < 3 2762 | else if (PyInt_Check(num_threads)) { 2763 | num_threads_long = PyInt_AsLong(num_threads); 2764 | } 2765 | #endif 2766 | else { 2767 | throw PyNormalizInputException("argument must be an integer"); 2768 | return NULL; 2769 | } 2770 | 2771 | num_threads_long = libnormaliz::set_thread_limit(num_threads_long); 2772 | 2773 | return PyLong_FromLong(num_threads_long); 2774 | 2775 | FUNC_END 2776 | } 2777 | 2778 | /*************************************************************************** 2779 | * 2780 | * Check for various features 2781 | * 2782 | ***************************************************************************/ 2783 | 2784 | static PyObject* NmzHasEAntic(PyObject* self) 2785 | { 2786 | #ifdef ENFNORMALIZ 2787 | Py_RETURN_TRUE; 2788 | #else 2789 | Py_RETURN_FALSE; 2790 | #endif 2791 | } 2792 | 2793 | static PyObject* NmzHasNauty(PyObject* self) 2794 | { 2795 | #ifdef NMZ_NAUTY 2796 | Py_RETURN_TRUE; 2797 | #else 2798 | Py_RETURN_FALSE; 2799 | #endif 2800 | } 2801 | 2802 | static PyObject* NmzHasFlint(PyObject* self) 2803 | { 2804 | #ifdef NMZ_FLINT 2805 | Py_RETURN_TRUE; 2806 | #else 2807 | Py_RETURN_FALSE; 2808 | #endif 2809 | } 2810 | 2811 | static PyObject* NmzHasCocoa(PyObject* self) 2812 | { 2813 | #ifdef NMZ_COCOA 2814 | Py_RETURN_TRUE; 2815 | #else 2816 | Py_RETURN_FALSE; 2817 | #endif 2818 | } 2819 | 2820 | /*************************************************************************** 2821 | * 2822 | * Write output file 2823 | * 2824 | ***************************************************************************/ 2825 | 2826 | static PyObject* NmzWriteOutputFile(PyObject* self, PyObject* args) 2827 | { 2828 | FUNC_BEGIN 2829 | 2830 | if ((!PyTuple_Check(args)) || (PyTuple_Size(args) != 2)) { 2831 | throw PyNormalizInputException( 2832 | "The arguments must be a cone and a string"); 2833 | return NULL; 2834 | } 2835 | 2836 | PyObject* cone_py = PyTuple_GetItem(args, 0); 2837 | PyObject* filename_py = PyTuple_GetItem(args, 1); 2838 | 2839 | string filename = PyUnicodeToString(filename_py); 2840 | 2841 | if (is_cone_mpz(cone_py)) { 2842 | Cone< mpz_class >* cone = get_cone_mpz(cone_py); 2843 | cone->write_cone_output(filename); 2844 | Py_RETURN_TRUE; 2845 | } 2846 | if (is_cone_long(cone_py)) { 2847 | Cone< long long >* cone = get_cone_long(cone_py); 2848 | cone->write_cone_output(filename); 2849 | Py_RETURN_TRUE; 2850 | } 2851 | #ifdef ENFNORMALIZ 2852 | if (is_cone_renf(cone_py)) { 2853 | Cone< renf_elem_class >* cone = get_cone_renf(cone_py); 2854 | cone->write_cone_output(filename); 2855 | Py_RETURN_TRUE; 2856 | } 2857 | #endif 2858 | Py_RETURN_FALSE; 2859 | 2860 | FUNC_END 2861 | } 2862 | 2863 | /*************************************************************************** 2864 | * 2865 | * Write file with precomputed data 2866 | * 2867 | ***************************************************************************/ 2868 | 2869 | static PyObject* NmzWritePrecompData(PyObject* self, PyObject* args) 2870 | { 2871 | FUNC_BEGIN 2872 | 2873 | if ((!PyTuple_Check(args)) || (PyTuple_Size(args) != 2)) { 2874 | throw PyNormalizInputException( 2875 | "The arguments must be a cone and a string"); 2876 | return NULL; 2877 | } 2878 | 2879 | PyObject* cone_py = PyTuple_GetItem(args, 0); 2880 | PyObject* filename_py = PyTuple_GetItem(args, 1); 2881 | 2882 | string filename = PyUnicodeToString(filename_py); 2883 | 2884 | if (is_cone_mpz(cone_py)) { 2885 | Cone< mpz_class >* cone = get_cone_mpz(cone_py); 2886 | cone->write_precomp_for_input(filename); 2887 | Py_RETURN_TRUE; 2888 | } 2889 | if (is_cone_long(cone_py)) { 2890 | Cone< long long >* cone = get_cone_long(cone_py); 2891 | cone->write_precomp_for_input(filename); 2892 | Py_RETURN_TRUE; 2893 | } 2894 | #ifdef ENFNORMALIZ 2895 | if (is_cone_renf(cone_py)) { 2896 | Cone< renf_elem_class >* cone = get_cone_renf(cone_py); 2897 | cone->write_precomp_for_input(filename); 2898 | Py_RETURN_TRUE; 2899 | } 2900 | #endif 2901 | Py_RETURN_FALSE; 2902 | 2903 | FUNC_END 2904 | } 2905 | 2906 | /*************************************************************************** 2907 | * 2908 | * Get renf minpoly and precision 2909 | * 2910 | ***************************************************************************/ 2911 | 2912 | static PyObject* NmzGetRenfInfo(PyObject* self, PyObject* args) 2913 | { 2914 | FUNC_BEGIN 2915 | #ifdef ENFNORMALIZ 2916 | if( (!PyTuple_Check(args)) || (PyTuple_Size(args) != 1) ){ 2917 | throw PyNormalizInputException( 2918 | "Only one argument allowed" 2919 | ); 2920 | return NULL; 2921 | } 2922 | PyObject* cone_py = PyTuple_GetItem(args, 0); 2923 | 2924 | if(!is_cone_renf(cone_py)){ 2925 | throw PyNormalizInputException( 2926 | "Only Renf cones allowed" 2927 | ); 2928 | return NULL; 2929 | } 2930 | 2931 | const renf_class* renf = get_cone_renf_renf(cone_py); 2932 | std::string minpoly_str; 2933 | minpoly_str = fmpq_poly_get_str_pretty(renf->get_renf()->nf->pol, renf->gen_name().c_str()); 2934 | std::string res1 = arb_get_str(renf->get_renf()->emb, 64, 0); 2935 | // long prec = renf->get_renf()->prec; 2936 | return PyTuple_Pack(2, StringToPyUnicode(minpoly_str), StringToPyUnicode(res1)); 2937 | #else 2938 | return NULL; 2939 | #endif 2940 | 2941 | FUNC_END 2942 | } 2943 | 2944 | /*************************************************************************** 2945 | * 2946 | * Get name of field generator 2947 | * 2948 | ***************************************************************************/ 2949 | 2950 | static PyObject* NmzFieldGenName(PyObject* self, PyObject* args) 2951 | { 2952 | FUNC_BEGIN 2953 | 2954 | if( (!PyTuple_Check(args)) || (PyTuple_Size(args) != 1) ){ 2955 | throw PyNormalizInputException( 2956 | "Only one argument allowed" 2957 | ); 2958 | return NULL; 2959 | } 2960 | PyObject* cone_py = PyTuple_GetItem(args, 0); 2961 | 2962 | std::string gen_name_string = ""; 2963 | 2964 | if (is_cone_mpz(cone_py)) { 2965 | return PyUnicode_FromString(gen_name_string.c_str()); 2966 | } 2967 | if (is_cone_long(cone_py)) { 2968 | return PyUnicode_FromString(gen_name_string.c_str()); 2969 | } 2970 | #ifdef ENFNORMALIZ 2971 | if (is_cone_renf(cone_py)) { 2972 | Cone< renf_elem_class >* cone_ptr = get_cone_renf(cone_py); 2973 | gen_name_string = cone_ptr->getRenfGenerator(); 2974 | return PyUnicode_FromString(gen_name_string.c_str()); 2975 | } 2976 | 2977 | #endif 2978 | 2979 | return NULL; // to make gcc happy 2980 | 2981 | FUNC_END 2982 | } 2983 | 2984 | /*************************************************************************** 2985 | * 2986 | * Python init stuff 2987 | * 2988 | ***************************************************************************/ 2989 | 2990 | struct module_state { 2991 | PyObject* error; 2992 | }; 2993 | 2994 | #if PY_MAJOR_VERSION >= 3 2995 | #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) 2996 | #else 2997 | #define GETSTATE(m) (&_state) 2998 | static struct module_state _state; 2999 | #endif 3000 | 3001 | static PyObject* error_out(PyObject* m) 3002 | { 3003 | struct module_state* st = GETSTATE(m); 3004 | PyErr_SetString(st->error, "something bad happened"); 3005 | return NULL; 3006 | } 3007 | 3008 | static PyMethodDef PyNormaliz_cppMethods[] = { 3009 | {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL}, 3010 | {"NmzCone", (PyCFunction)_NmzCone, METH_VARARGS | METH_KEYWORDS, 3011 | "Create a cone"}, 3012 | {"NmzConeCopy", (PyCFunction)_NmzConeCopy, METH_VARARGS, 3013 | "Copy an existing cone"}, 3014 | {"NmzCompute", (PyCFunction)_NmzCompute_Outer, METH_VARARGS, 3015 | "Compute some stuff"}, 3016 | {"NmzIsComputed", (PyCFunction)NmzIsComputed_Outer, METH_VARARGS, 3017 | "Check if property is computed "}, 3018 | {"NmzSetGrading", (PyCFunction)NmzSetGrading, METH_VARARGS, 3019 | "Reset the grading of a cone"}, 3020 | {"NmzSetProjectionCoords", (PyCFunction)NmzSetProjectionCoords, METH_VARARGS, 3021 | "Reset the projection coordinates"}, 3022 | {"NmzResult", (PyCFunction)_NmzResult, METH_VARARGS | METH_KEYWORDS, 3023 | "Return cone property"}, 3024 | {"NmzSetVerboseDefault", (PyCFunction)NmzSetVerboseDefault, METH_VARARGS, 3025 | "Set verbosity"}, 3026 | {"NmzSetVerbose", (PyCFunction)NmzSetVerbose_Outer, METH_VARARGS, 3027 | "Set verbosity of cone"}, 3028 | {"NmzListConeProperties", (PyCFunction)NmzListConeProperties, METH_NOARGS, 3029 | "List all available properties"}, 3030 | // {"NmzHilbertSeries", (PyCFunction)NmzHilbertSeries_Outer, METH_VARARGS, 3031 | // "Returns Hilbert series, either HSOP or not"}, 3032 | {"NmzGetPolynomial", (PyCFunction)NmzGetPolynomial, METH_VARARGS, 3033 | "Returns grading polynomial"}, 3034 | {"NmzSymmetrizedCone", (PyCFunction)NmzSymmetrizedCone, METH_VARARGS, 3035 | "Returns symmetrized cone"}, 3036 | {"NmzSetNumberOfNormalizThreads", 3037 | (PyCFunction)NmzSetNumberOfNormalizThreads, METH_VARARGS, 3038 | "Sets the Normaliz thread limit"}, 3039 | {"NmzSetNrCoeffQuasiPol", (PyCFunction)NmzSetNrCoeffQuasiPol, 3040 | METH_VARARGS, "Sets the number of computed coefficients for the quasi-polynomial"}, 3041 | {"NmzSetDecimalDigits", (PyCFunction)NmzSetDecimalDigits, 3042 | METH_VARARGS, "Sets the number of decimal digits for fixed precision"}, 3043 | {"NmzSetPolynomial", (PyCFunction)NmzSetPolynomial, 3044 | METH_VARARGS, "Sets the polynomial for integration and weighted series"}, 3045 | {"NmzSetPolynomialEquations", (PyCFunction)NmzSetPolynomialEquations, 3046 | METH_VARARGS, "Sets the polynomial equations for lattice points"}, 3047 | {"NmzSetPolynomialInequalities", (PyCFunction)NmzSetPolynomialInequalities, 3048 | METH_VARARGS, "Sets the polynomial inequalities for lattice points"}, 3049 | {"NmzSetFaceCodimBound", (PyCFunction)NmzSetFaceCodimBound, 3050 | METH_VARARGS, "Sets the maximal codimension for the computed faces"}, 3051 | {"NmzSetModularGrading", (PyCFunction)NmzSetModularGrading, 3052 | METH_VARARGS, "Sets the maximal codimension for the computed faces"}, 3053 | {"NmzSetChosenFusionRing", (PyCFunction)NmzSetChosenFusionRing, 3054 | METH_VARARGS, "Picks a fusion ring (counting from 1)"}, 3055 | {"NmzSetGBDegreeBound", (PyCFunction)NmzSetGBDegreeBound, 3056 | METH_VARARGS, "Sets the maximal degree for binomials in Gröbner and Markov bases"}, 3057 | {"NmzSetGBMinDegree", (PyCFunction)NmzSetGBMinDegree, 3058 | METH_VARARGS, "Sets the minimal degree for binomials in Gröbner and Markov bases"}, 3059 | {"NmzGetHilbertSeriesExpansion", 3060 | (PyCFunction)NmzGetHilbertSeriesExpansion, METH_VARARGS, 3061 | "Returns expansion of the hilbert series"}, 3062 | {"NmzGetEhrhartSeriesExpansion", 3063 | (PyCFunction)NmzGetEhrhartSeriesExpansion, METH_VARARGS, 3064 | "Returns expansion of the Ehrhart series"}, 3065 | {"NmzGetWeightedEhrhartSeriesExpansion", 3066 | (PyCFunction)NmzGetWeightedEhrhartSeriesExpansion, METH_VARARGS, 3067 | "Returns expansion of the weighted Ehrhart series"}, 3068 | 3069 | {"NmzHasEAntic", (PyCFunction)NmzHasEAntic, METH_NOARGS, 3070 | "Returns true if (Py)Normaliz was compiled with e-antic support"}, 3071 | {"NmzHasNauty", (PyCFunction)NmzHasNauty, METH_NOARGS, 3072 | "Returns true if (Py)Normaliz was compiled with nauty support"}, 3073 | {"NmzHasFlint", (PyCFunction)NmzHasFlint, METH_NOARGS, 3074 | "Returns true if (Py)Normaliz was compiled with Flint support"}, 3075 | {"NmzHasCocoa", (PyCFunction)NmzHasCocoa, METH_NOARGS, 3076 | "Returns true if (Py)Normaliz was compiled with CoCoA support"}, 3077 | 3078 | {"NmzWriteOutputFile", (PyCFunction)NmzWriteOutputFile, METH_VARARGS, 3079 | "Prints the Normaliz cone output into a file"}, 3080 | {"NmzWritePrecompData", (PyCFunction)NmzWritePrecompData, METH_VARARGS, 3081 | "Prints the Normaliz cone precomputed data for further input"}, 3082 | 3083 | {"NmzGetRenfInfo", (PyCFunction)NmzGetRenfInfo, METH_VARARGS, 3084 | "Outputs info of the number field associated to a renf cone"}, 3085 | {"NmzFieldGenName", (PyCFunction)NmzFieldGenName, METH_VARARGS, 3086 | "Returns name of field generator"}, 3087 | 3088 | {"NmzModifyCone", (PyCFunction)_NmzModify_Outer, METH_VARARGS, 3089 | "Modifies a given input property of a cone using a new matrix"}, 3090 | { 3091 | NULL, 3092 | } /* Sentinel */ 3093 | }; 3094 | 3095 | 3096 | #if PY_MAJOR_VERSION >= 3 3097 | 3098 | static int PyNormaliz_cpp_traverse(PyObject* m, visitproc visit, void* arg) 3099 | { 3100 | Py_VISIT(GETSTATE(m)->error); 3101 | return 0; 3102 | } 3103 | 3104 | static int PyNormaliz_cpp_clear(PyObject* m) 3105 | { 3106 | Py_CLEAR(GETSTATE(m)->error); 3107 | return 0; 3108 | } 3109 | 3110 | 3111 | static struct PyModuleDef moduledef = { 3112 | PyModuleDef_HEAD_INIT, "PyNormaliz_cpp", NULL, 3113 | sizeof(struct module_state), PyNormaliz_cppMethods, NULL, 3114 | PyNormaliz_cpp_traverse, PyNormaliz_cpp_clear, NULL}; 3115 | 3116 | #define INITERROR return NULL 3117 | 3118 | PyMODINIT_FUNC PyInit_PyNormaliz_cpp(void) 3119 | 3120 | #else 3121 | #define INITERROR return 3122 | 3123 | extern "C" void initPyNormaliz_cpp(void) 3124 | #endif 3125 | { 3126 | #if PY_MAJOR_VERSION >= 3 3127 | PyObject* module = PyModule_Create(&moduledef); 3128 | #else 3129 | PyObject* module = Py_InitModule("PyNormaliz_cpp", PyNormaliz_cppMethods); 3130 | #endif 3131 | 3132 | if (module == NULL) 3133 | INITERROR; 3134 | struct module_state* st = GETSTATE(module); 3135 | 3136 | st->error = PyErr_NewException( 3137 | const_cast< char* >("PyNormaliz_cpp.INITError"), NULL, NULL); 3138 | if (st->error == NULL) { 3139 | Py_DECREF(module); 3140 | INITERROR; 3141 | } 3142 | 3143 | NormalizError = PyErr_NewException( 3144 | const_cast< char* >("PyNormaliz_cpp.NormalizError"), NULL, NULL); 3145 | Py_INCREF(NormalizError); 3146 | PyNormaliz_cppError = PyErr_NewException( 3147 | const_cast< char* >("PyNormaliz_cpp.NormalizInterfaceError"), NULL, 3148 | NULL); 3149 | Py_INCREF(PyNormaliz_cppError); 3150 | 3151 | PyModule_AddObject(module, "normaliz_error", NormalizError); 3152 | PyModule_AddObject(module, "pynormaliz_error", PyNormaliz_cppError); 3153 | 3154 | #if PY_MAJOR_VERSION >= 3 3155 | return module; 3156 | #endif 3157 | } 3158 | -------------------------------------------------------------------------------- /PyNormaliz.py: -------------------------------------------------------------------------------- 1 | # encoding=utf8 2 | 3 | import sys 4 | 5 | import PyNormaliz_cpp 6 | from PyNormaliz_cpp import * 7 | 8 | def fill_blanks(x,s): 9 | t = len(x) 10 | if t >= s: 11 | return x 12 | out = "" 13 | for i in range(s-t): 14 | out = " " + out 15 | out = out + x 16 | return out 17 | 18 | def print_perms_and_orbits(data, name): 19 | print("permutations of ", name) 20 | for i in range(len(data[0])): 21 | print(i, ": ", data[0][i]) 22 | print("orbits of ", name) 23 | for i in range(len(data[1])): 24 | print(i, ": ", data[1][i]) 25 | return 26 | 27 | 28 | def print_automs(Automs): 29 | print("order ", Automs[0]) 30 | if Automs[1]: 31 | if Automs[2]: 32 | print("automorphisms are integral") 33 | else: 34 | print("automorphisms are not integral") 35 | else: 36 | print("integrality of automorphisms unknown") 37 | 38 | gen_name ="extreme rays of (recession) cone" 39 | if len(Automs) == 7: 40 | gen_name = "input vectors"; 41 | lf_name = "support hyperplanes" 42 | if len(Automs) == 7: 43 | lf_name = "coordinates" 44 | 45 | if len(Automs[3][0]) >0: 46 | print_perms_and_orbits(Automs[3],gen_name) 47 | if len(Automs[4][0]) >0: 48 | print_perms_and_orbits(Automs[4],"vertices of polyhedron") 49 | if len(Automs[5][0]) >0: 50 | print_perms_and_orbits(Automs[5],lf_name) 51 | 52 | if len(Automs) == 7: 53 | print("input vectors") 54 | print_matrix(Automs[6]) 55 | return 56 | 57 | def print_Stanley_dec(dec): 58 | print("generators") 59 | print_matrix(dec[1]) 60 | print("simlices and offsets") 61 | for i in range(len(dec[0])): 62 | print(dec[0][i][0]) 63 | print() 64 | print_matrix(dec[0][i][1]) 65 | print("-----------") 66 | return 67 | 68 | def print_matrix(M): 69 | if not isinstance(M,list): 70 | print("print_matrix applied to non-matrix") 71 | return 72 | if len(M) == 0: 73 | return 74 | if not isinstance(M[0],list): 75 | print("pretty_print applied to non-matrix") 76 | return 77 | L0 = len(M[0]) 78 | CL = [] 79 | for k in range(len(M[0])): 80 | CL = CL + [0] 81 | for i in range(len(M)): 82 | current = M[i] 83 | if not isinstance(current,list) or len(current) != L0: 84 | print("pretty_print applied to non-matrix") 85 | return 86 | for j in range(len(current)): 87 | x = current[j] 88 | x = str(x) 89 | l = len(x) 90 | if l > CL[j]: 91 | CL[j] = l 92 | for i in range(len(M)): 93 | current = M[i] 94 | current_line ="" 95 | for j in range(len(current)): 96 | s= 0 97 | if j > 0: 98 | s= 1 99 | x = current[j] 100 | x = str(x) 101 | x = fill_blanks(x,s+CL[j]) 102 | current_line = current_line + x 103 | print(current_line) 104 | return 105 | 106 | 107 | def our_rat_handler(list): 108 | if list[0] == 0: 109 | return 0 110 | if list[1] == 1: 111 | return list[0] 112 | return str(list[0])+"/"+str(list[1]) 113 | 114 | 115 | def our_renf_handler(list): 116 | out = "" 117 | non_zero = False 118 | for i in range(len(list)): 119 | j = len(list) - 1 -i 120 | current = str(list[j]) 121 | if current[0] == '0': 122 | if non_zero or j !=0: 123 | continue 124 | else: 125 | out="0" 126 | return out 127 | non_zero = True 128 | sign ="+" 129 | if current[0] == '-' or out == "": 130 | sign = "" 131 | if j>0 and current == "-1": 132 | sign ="-" 133 | if j == 0: 134 | power = "" 135 | if j == 1: 136 | power = name_of_indeterminate 137 | if j > 1: 138 | power = name_of_indeterminate + "^"+str(j) 139 | coeff = current 140 | star = "*" 141 | if coeff == "1" or coeff == "-1" or j==0: 142 | star = "" 143 | if (coeff == "1" or coeff == "-1") and j>0: 144 | coeff = "" 145 | out = out + sign + coeff + star +power 146 | return out 147 | 148 | def our_float_handler(x): 149 | return "{:.4f}".format(x) 150 | 151 | def PrettyPolynomialTuple(numCoefficients, denCoefficients): 152 | """ 153 | Strings for numerator and denominator of the a Hilbert series. 154 | 155 | Parameters 156 | ---------- 157 | numCoefficients : list 158 | The coefficients for the numerator. 159 | denCofficients : list 160 | The coefficients for the denominator where the value represents the 161 | exponent of 't' and the frequency indicates the outer coefficient. 162 | 163 | Returns 164 | ------- 165 | PrettyPolynomialTuple: tuple of strings 166 | 167 | Examples 168 | -------- 169 | 170 | >>> numCoefficients = [3, 7, 4, -4, -6, 5] 171 | >>> denCoefficients = [1, 1, 2, 2, 2, 4] 172 | >>> PrettyPolynomialTuple(numCoefficients,denCoefficients) 173 | 174 | ('(3 + 7t + 4t² - 4t³ - 6t⁴ + 5t⁵)', '(1 - t)² (1 - t²)³ (1 - t⁴)') 175 | 176 | """ 177 | def to_sup(s): 178 | if str(s) == '1': 179 | return '' 180 | if sys.version == 3: 181 | sups = {u'0': u'\u2070', 182 | u'1': u'\xb9', 183 | u'2': u'\xb2', 184 | u'3': u'\xb3', 185 | u'4': u'\u2074', 186 | u'5': u'\u2075', 187 | u'6': u'\u2076', 188 | u'7': u'\u2077', 189 | u'8': u'\u2078', 190 | u'9': u'\u2079'} 191 | # lose the list comprehension 192 | return ''.join(sups.get(str(char), str(char)) for char in str(s)) 193 | 194 | return "^"+str(s) 195 | 196 | def getNumerator(coefficients): 197 | 198 | numerator = '' 199 | 200 | def isPositive(x): 201 | return x > 0 202 | 203 | firstNonZero = next( 204 | (i for i, x in enumerate(coefficients) if x != 0), 0) 205 | for exp, coefficient in enumerate(coefficients): 206 | if coefficient == 0: 207 | continue 208 | coeff_str = str(abs(coefficient)) 209 | if exp != 0: 210 | if coeff_str == "1": 211 | coeff_str = " " 212 | # Exponent is 0 so keep only the coefficient 213 | if exp == 0: 214 | numerator += '({}{!s}'.format('-' if not isPositive(coefficient) 215 | else '',coeff_str) 216 | # Only include sign if `coefficient` is negative 217 | elif exp is firstNonZero: 218 | numerator += '{}{!s}t{}'.format('-' if not isPositive( 219 | coefficient) else '', coeff_str, to_sup(exp)) 220 | else: 221 | numerator += ' {}{!s}t{}'.format('+ ' if isPositive( 222 | coefficient) else '- ',coeff_str, to_sup(exp)) 223 | numerator += ')' 224 | return numerator 225 | 226 | def getDenominator(coefficients): 227 | exponents = [(inner, coefficients.count(inner)) 228 | for inner in set(coefficients)] 229 | denominator = ' '.join('(1 - t{}){}'. format(to_sup(x[0]) if x[0] != 1 else '', to_sup(x[1]) if x[1] != 1 else '') for x in exponents) 230 | return denominator 231 | 232 | num = getNumerator(numCoefficients) 233 | den = getDenominator(denCoefficients) 234 | prettyPolynomial = (num, den) 235 | return prettyPolynomial 236 | 237 | def PrintPrettyHilbertSeries(numCoefficients, denCoefficients): 238 | """ 239 | Make a pretty Hilbert series string 240 | 241 | Parameters 242 | ---------- 243 | numCoefficients : list of ints 244 | The coefficients for the numerator. 245 | denCofficients : list of ints 246 | The coefficients for the denominator where the value represents 247 | the exponent of 't' and the frequency indicates the outer 248 | coefficient. 249 | 250 | Returns 251 | ------- 252 | PrintPrettyHilbertSeries : string 253 | 254 | Examples 255 | -------- 256 | 257 | >>> numCoefficients = [3, 7, 4, -4, -6, 5] 258 | >>> deCoefficients = [1, 1, 2, 2, 2, 4] 259 | >>> PrintPrettyHilbertSeries(numCoefficients,deCoefficients) 260 | 261 | (3 + 7t + 4t² - 4t³ - 6t⁴ + 5t⁵) 262 | -------------------------------- 263 | (1 - t)² (1 - t²)³ (1 - t⁴) 264 | 265 | """ 266 | num, den = PrettyPolynomialTuple(numCoefficients, denCoefficients) 267 | prettyPolynomial = '{:^}\n{:-^{width}}\n{:^{width}}'.format( 268 | num, '', den, width=max(len(den),len(num))) 269 | return prettyPolynomial 270 | 271 | def print_series(series): 272 | shift=series[2] 273 | Shift = [] 274 | if shift >= 0: 275 | Shift=[ 0 for x in range(1,shift) ] 276 | numerator=Shift+series[0] 277 | denominator=series[1] 278 | print(PrintPrettyHilbertSeries(numerator,denominator)) 279 | if shift < 0: 280 | print("shift ", shift) 281 | if len(series) > 3 and series[3] !=1: 282 | print("dvide numerator by ",series[3]) 283 | return 284 | 285 | def print_quasipol(poly): 286 | pp = [] 287 | for i in range(len(poly)-1): 288 | pp = pp + [poly[i]] 289 | print_matrix(pp) 290 | if poly[len(poly)-1] != 1: 291 | print ("divide all coefficients by ", poly[len(poly)-1]) 292 | return 293 | 294 | 295 | name_of_indeterminate = "" 296 | 297 | class Cone: 298 | 299 | def __init__(self,**kwargs): 300 | global name_of_indeterminate 301 | pop_list = [] 302 | for entry in kwargs.items(): 303 | current_input=entry[1]; 304 | key = entry[0] 305 | if type(current_input) == bool and current_input == True: 306 | kwargs[key] = current_input = [[]] 307 | elif type(current_input) == bool and current_input == False: 308 | poplist = pop_list + [key] 309 | for k in pop_list: 310 | kwargs.pop(k) 311 | self.cone = PyNormaliz_cpp.NmzCone(**kwargs) 312 | name_of_indeterminate = PyNormaliz_cpp.NmzFieldGenName(self.cone) 313 | 314 | def ModifyCone(self, *args): 315 | PyNormaliz_cpp.NmzModifyCone(self.cone, *args) 316 | 317 | def __process_keyword_args(self, keywords): 318 | input_list = [] 319 | for i in keywords: 320 | if keywords[i] == True: 321 | input_list.append(i) 322 | return input_list 323 | 324 | def print_properties(self): 325 | props = PyNormaliz_cpp.NmzListConeProperties() 326 | goals = props[0] 327 | for x in goals: 328 | if x == "Generators": 329 | continue 330 | if (PyNormaliz_cpp.NmzIsComputed(self.cone, x)): 331 | print(x + ":") 332 | print(PyNormaliz_cpp.NmzResult(self.cone, x)) 333 | 334 | def __str__(self): 335 | return "" 336 | 337 | def __repr__(self): 338 | return "" 339 | 340 | def GetFieldGenName(self): 341 | return PyNormaliz_cpp.NmzFieldGenName(self.cone) 342 | 343 | def Compute(self, *args): 344 | return PyNormaliz_cpp.NmzCompute(self.cone, args) 345 | 346 | def IsComputed(self, *args): 347 | if len(args) != 1: 348 | raise ValueError("IsComputed must have exactly one argument") 349 | return PyNormaliz_cpp.NmzIsComputed(self.cone, args[0]) 350 | 351 | def SetVerbose(self, verbose=True): 352 | return NmzSetVerbose(self.cone, verbose) 353 | 354 | # This one is not like the others! 355 | def IntegerHull(self): 356 | input_list=["IntegerHull"] 357 | PyNormaliz_cpp.NmzCompute(self.cone, input_list) 358 | new_inner_cone = PyNormaliz_cpp.NmzResult(self.cone, "IntegerHull") 359 | return_cone = Cone.__new__(Cone) 360 | return_cone.cone = new_inner_cone 361 | return return_cone 362 | 363 | def ProjectCone(self): 364 | input_list=["ProjectCone"] 365 | PyNormaliz_cpp.NmzCompute(self.cone, input_list) 366 | new_inner_cone = PyNormaliz_cpp.NmzResult(self.cone, "ProjectCone") 367 | return_cone = Cone.__new__(Cone) 368 | return_cone.cone = new_inner_cone 369 | return return_cone 370 | 371 | def SymmetrizedCone(self, **kwargs): 372 | new_inner_cone = PyNormaliz_cpp.NmzSymmetrizedCone(self.cone) 373 | if new_inner_cone == None: 374 | return None 375 | return_cone = Cone.__new__(Cone) 376 | return_cone.cone = new_inner_cone 377 | return return_cone 378 | 379 | def Polynomial(self): 380 | return PyNormaliz_cpp.NmzGetPolynomial(self.cone) 381 | 382 | def SetNrCoeffQuasiPol(self, bound=-1): 383 | return PyNormaliz_cpp.NmzSetNrCoeffQuasiPol(self.cone, bound) 384 | 385 | def SetFaceCodimBound(self, bound=-1): 386 | return PyNormaliz_cpp.NmzSetFaceCodimBound(self.cone, bound) 387 | 388 | def SetModularGrading(self, mod_gr=-1): 389 | return PyNormaliz_cpp.NmzSetModularGrading(self.cone, mod_gr) 390 | 391 | def SetChosenFusionRing(self, chosen_ring=-1): 392 | return PyNormaliz_cpp.NmzSetChosenFusionRing(self.cone, chosen_ring) 393 | 394 | def SetGBDegreeBound(self, bound=-1): 395 | return PyNormaliz_cpp.NmzSetGBDegreeBound(self.cone, bound) 396 | 397 | def SetGBMinDegree(self, bound=-1): 398 | return PyNormaliz_cpp.NmzSetGBMinDegree(self.cone, bound) 399 | 400 | def SetDecimalDigits(self, digits=100): 401 | return PyNormaliz_cpp.NmzSetDecimalDigits(self.cone, digits) 402 | 403 | def SetPolynomial(self, poly =""): 404 | return PyNormaliz_cpp.NmzSetPolynomial(self.cone, poly) 405 | 406 | def SetPolynomialEquations(self, polys =[]): 407 | return PyNormaliz_cpp.NmzSetPolynomialEquations(self.cone, polys) 408 | 409 | def SetPolynomialInequalities(self, polys =[]): 410 | return PyNormaliz_cpp.NmzSetPolynomialInequalities(self.cone, polys) 411 | 412 | def SetGrading(self, grading): 413 | return PyNormaliz_cpp.NmzSetGrading(self.cone, grading) 414 | 415 | def HilbertSeriesExpansion(self,degree): 416 | return NmzGetHilbertSeriesExpansion(self.cone,degree) 417 | 418 | def EhrhartSeriesExpansion(self,degree): 419 | return NmzGetEhrhartSeriesExpansion(self.cone,degree) 420 | 421 | def WeightedEhrhartSeriesExpansion(self,degree): 422 | return NmzGetWeightedEhrhartSeriesExpansion(self.cone,degree) 423 | 424 | def WriteOutputFile(self, project): 425 | return NmzWriteOutputFile(self.cone, project) 426 | 427 | def WritePrecompData(self, project): 428 | return NmzWritePrecompData(self.cone, project) 429 | 430 | def NumberFieldData(self): 431 | return NmzGetRenfInfo(self.cone) 432 | 433 | def _generic_getter(self, name, **kwargs): 434 | input_list = self.__process_keyword_args(kwargs) 435 | input_list.append(name) 436 | PyNormaliz_cpp.NmzCompute(self.cone, input_list) 437 | return PyNormaliz_cpp.NmzResult(self.cone, name,RationalHandler = our_rat_handler, \ 438 | NumberfieldElementHandler=our_renf_handler, FloatHandler = our_float_handler) 439 | 440 | # Generate getters for a bunch of Normalize properties 441 | def add_dyn_getter(name): 442 | if hasattr(Cone, name): 443 | return 444 | def inner(self, **kwargs): 445 | return self._generic_getter(name, **kwargs) 446 | inner.__doc__ = "docstring for %s" % name 447 | inner.__name__ = name 448 | setattr(Cone, name, inner) 449 | 450 | for name in PyNormaliz_cpp.NmzListConeProperties()[0]: 451 | add_dyn_getter(name) 452 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://github.com/Normaliz/PyNormaliz/workflows/Run%20tests/badge.svg)](https://github.com/Normaliz/PyNormaliz/actions) 2 | 3 | # PyNormaliz - A python interface to Normaliz 4 | 5 | 6 | PyNormaliz provides an interface to [Normaliz](https://www.normaliz.uni-osnabrueck.de) via libNormaliz. 7 | It offers the complete functionality of Normaliz, and can be used interactively from python. 8 | For a first example, see [this introduction](doc/PyNormaliz_Tutorial.pdf) by Richard Sieg (Slightly outdated: for the installation follow the instructions below). 9 | 10 | A full documentation is contained in [Appendix E](doc/PyNormaliz.pdf) of the Normaliz manual. 11 | 12 | 13 | ## Requirements 14 | 15 | * python 3.4 or higher 16 | * Normaliz 3.10.2 or higher 17 | 18 | The source packages of the Normaliz releases contain PyNormaliz. 19 | 20 | ## Installation 21 | 22 | The PyNormaliz install script assumes that you have executed 23 | 24 | ./install_normaliz_with_eantic.sh 25 | 26 | within the Normaliz directory. To install PyNormaliz navigate to the Normaliz directory and type 27 | 28 | ./install_pynormaliz.sh --user 29 | 30 | ## Usage 31 | 32 | The command Cone creates a cone (and a lattice), and the member functions 33 | of Cone compute its properties. For a full list of input and output 34 | properties, see the Normaliz manual. 35 | 36 | Start by 37 | 38 | import PyNormaliz 39 | from PyNormaliz import * 40 | 41 | To create a simple example, type 42 | 43 | C = Cone(cone = [[1,0],[0,1]]) 44 | 45 | 46 | All possible Normaliz input types can be given as keyword arguments. 47 | 48 | The member functions allow the computation of the data of our cone. For example, 49 | 50 | C.HilbertBasis() 51 | 52 | returns what its name says: 53 | 54 | [[0, 1], [1, 0]] 55 | 56 | is the matrix of the two Hilbert basis vectors. The output matrices of PyNormaliz can be used also in Normaliz input files. 57 | 58 | One can pass options to the compute functions as in 59 | 60 | C.HilbertSeries(HSOP = True) 61 | 62 | Note that some Normaliz output types must be specially encoded for python. Our Hilbert Series is returned as 63 | 64 | [[1], [1, 1], 0] 65 | 66 | to be read as follows: [1] is the numerator polynomial, [1,1] is the vector of exponents of t that occur in the denominator, which is (1-t)(1-t) in our case, and 0 is the shift. So the Hilbert series is given by the rational function 1/(1-t)(1-t). (Also see [this introduction](doc/PyNormaliz_Tutorial.pdf).) But we can use 67 | 68 | print_series(C.HilbertSeries(HSOP = True)) 69 | 70 | with the result 71 | 72 | (1) 73 | --------- 74 | (1 - t)^2 75 | 76 | 77 | One can also compute several data simultaneously and specify options ("PrimalMode" only added as an example, not because it is particularly useful here): 78 | 79 | C.Compute("LatticePoints", "Volume", "PrimalMode") 80 | 81 | Then 82 | 83 | C.Volume() 84 | 85 | with the result 86 | 87 | 1 88 | 89 | This is the lattice length of the diagonal in the square. The euclidean length, that has been computed simultaneously, is returned by 90 | 91 | C.EuclideanVolume() 92 | 93 | with the expected value 94 | 95 | '1.4142' 96 | 97 | Floating point numbers are formatted with 4 decimal places and returned as strings (may change). If you want the euclideal volume at the maximum floating point precision, you can use the low level interface which is intermediate between the class Cone and libnormaliz: 98 | 99 | NmzResult(C.cone,"EuclideanVolume") 100 | 1.4142135623730951 101 | 102 | One can find out whether a single goal has been computed by asking 103 | 104 | C.IsComputed("Automorphisms") 105 | False 106 | 107 | If you use Compute instead of IsComputed, then Normaliz tries to compute the goal, and there are situations in which the computation is undesirable. 108 | 109 | Algebraic polyhedra can be computed by PyNormaliz as well: 110 | 111 | nf = [ "a2-2", "a", "1.4+/-0.1" ] 112 | D = Cone( number_field = nf, cone = [["1/7a+3/2", "-5a"],["4/83a-1","97/81"]]) 113 | 114 | It is important to note that fractions and algebraic numbers must be encoded as strings for the input. 115 | 116 | S = D.SupportHyperplanes() 117 | S 118 | [['-1470/433*a+280/433', '-1'], ['-32204/555417*a-668233/555417', '-1']] 119 | 120 | Very hard to read! Somewhat better: 121 | 122 | print_matrix(S) 123 | 124 | -1470/433*a+280/433 -1 125 | -32204/555417*a-668233/555417 -1 126 | 127 | But we can also get floating point approximations: 128 | 129 | print_matrix(D.SuppHypsFloat()) 130 | 131 | -4.1545 -1.0000 132 | -1.2851 -1.0000 133 | 134 | By using Python functions, the functionality of Normaliz can be extended. For example, 135 | 136 | def intersection(cone1, cone2): 137 | intersection_ineq = cone1.SupportHyperplanes()+cone2.SupportHyperplanes() 138 | intersection_equat = cone1.Equations()+cone2.Equations() 139 | C = Cone(inequalities = intersection_ineq, equations = intersection_equat) 140 | return C 141 | 142 | computes the intersection of two cones. So 143 | 144 | C1 = Cone(cone=[[1,2],[2,1]]) 145 | C2 = Cone(cone=[[1,1],[1,3]]) 146 | intersection(C1,C2).ExtremeRays() 147 | 148 | yeilds the result 149 | 150 | [[1, 1], [1, 2]] 151 | 152 | If you want to see what Normaliz is doing (especually in longer computations) activate the terminal output by 153 | 154 | C.setVerbose(True) 155 | -------------------------------------------------------------------------------- /doc/PyNormaliz.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Normaliz/PyNormaliz/f5dc544369312c0bc3a86ef5facfb2b4ff8d9ddc/doc/PyNormaliz.pdf -------------------------------------------------------------------------------- /doc/PyNormaliz_Tutorial.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "deletable": true, 7 | "editable": true, 8 | "slideshow": { 9 | "slide_type": "slide" 10 | } 11 | }, 12 | "source": [ 13 | "# Introducing PyNormaliz \n", 14 | "\n", 15 | "(Winfried Bruns, Sebastian Gutsche, Justhin Shenk, Richard Sieg)\n", 16 | "\n", 17 | "This small tutorial introduces the main syntax of the Python interface PyNormaliz for Normaliz.\n", 18 | "\n", 19 | "To install PyNormaliz on your machine, download the PyNormaliz and run \n", 20 | "
\n",
 21 |     "python setup.py install\n",
 22 |     "
\n", 23 | "If you are using python3 you might need to enter python3 instead of python." 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": { 29 | "deletable": true, 30 | "editable": true, 31 | "slideshow": { 32 | "slide_type": "slide" 33 | } 34 | }, 35 | "source": [ 36 | "## Example 1: A cone in dimension 2\n", 37 | "We want to investigate the cone $C=\\mathbb{R}_{+}(2,1)+\\mathbb{R}_{+}(1,3)\\subset\\mathbb{R}^2$.\n", 38 | "\n", 39 | "In the cone constructor of PyNormaliz, we specify the input type (`cone`) and an input matrix for this input type. \n", 40 | "\n", 41 | "To compute its Hilbert basis we use the point operator and call `HilbertBasis()` on our cone." 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 1, 47 | "metadata": { 48 | "collapsed": false, 49 | "deletable": true, 50 | "editable": true, 51 | "scrolled": false, 52 | "slideshow": { 53 | "slide_type": "fragment" 54 | } 55 | }, 56 | "outputs": [ 57 | { 58 | "data": { 59 | "text/plain": [ 60 | "[[1, 1], [1, 2], [1, 3], [2, 1]]" 61 | ] 62 | }, 63 | "execution_count": 1, 64 | "metadata": {}, 65 | "output_type": "execute_result" 66 | } 67 | ], 68 | "source": [ 69 | "from PyNormaliz import * # or import PyNormaliz\n", 70 | "\n", 71 | "gen = [[1,3],[2,1]]\n", 72 | "C = Cone(cone=gen)\n", 73 | "C.HilbertBasis()" 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": { 79 | "deletable": true, 80 | "editable": true, 81 | "slideshow": { 82 | "slide_type": "subslide" 83 | } 84 | }, 85 | "source": [ 86 | "We can also use inequalities as an input. We also check that the extreme rays of the new cone are really the generators of the previous one." 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 2, 92 | "metadata": { 93 | "collapsed": false, 94 | "deletable": true, 95 | "editable": true, 96 | "slideshow": { 97 | "slide_type": "fragment" 98 | } 99 | }, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | "True\n", 106 | "[[1, 1], [1, 2], [1, 3], [2, 1]]\n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "ineq = [[-1,2],[3,-1]]\n", 112 | "C2 = Cone(inequalities=ineq)\n", 113 | "gen2 = C2.ExtremeRays()\n", 114 | "print(gen==gen2)\n", 115 | "HB2 = C2.HilbertBasis()\n", 116 | "print(HB2)" 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "metadata": {}, 122 | "source": [ 123 | "The general construction of objects in PyNormaliz follows the same fashion: You can generate a cone via `Cone` and then specify the usual input type(s) as parameters with the input data as `type=input data`. Once the cone is created, all its possible data is accessible using the `.` operator, like `C.HilbertBasis()`. \n", 124 | "\n", 125 | "Basically all input types and output data is available. An overview is given in the usual manual." 126 | ] 127 | }, 128 | { 129 | "cell_type": "markdown", 130 | "metadata": { 131 | "deletable": true, 132 | "editable": true, 133 | "slideshow": { 134 | "slide_type": "slide" 135 | } 136 | }, 137 | "source": [ 138 | "# Example 2: A lattice polytope\n", 139 | "Now we investigate a lattice simplex, which is not normal/integrally closed.\n", 140 | "\n", 141 | "The input type is `polytope`. Note that we do not need a homogenizing variable but really specify the points in their actual dimension.\n", 142 | "\n", 143 | "We compute its Hilbert series and Hilbert polynomial, which are also sometimes referred to as Ehrhart series and polynomial:\n", 144 | "\n", 145 | "Hilbert series: $H(t)=\\frac{1+14t+15t^2}{(1-t)^4}$\n", 146 | "\n", 147 | "Hilbert polynomial: $p(k)=1+4k+8k^2+5k^3$\n" 148 | ] 149 | }, 150 | { 151 | "cell_type": "code", 152 | "execution_count": 3, 153 | "metadata": { 154 | "collapsed": false, 155 | "deletable": true, 156 | "editable": true, 157 | "slideshow": { 158 | "slide_type": "fragment" 159 | } 160 | }, 161 | "outputs": [ 162 | { 163 | "name": "stdout", 164 | "output_type": "stream", 165 | "text": [ 166 | "19\n", 167 | "False\n", 168 | "[[1, 14, 15], [1, 1, 1, 1], 0]\n", 169 | "[[1, 4, 8, 5], 1]\n" 170 | ] 171 | } 172 | ], 173 | "source": [ 174 | "vertices = [[0,0,0],[2,0,0],[0,3,0],[0,0,5]]\n", 175 | "poly = Cone(polytope=vertices)\n", 176 | "HB = poly.HilbertBasis()\n", 177 | "print(len(HB))\n", 178 | "print(poly.IsDeg1HilbertBasis())\n", 179 | "print(poly.HilbertSeries()) \n", 180 | "print(poly.HilbertQuasiPolynomial())" 181 | ] 182 | }, 183 | { 184 | "cell_type": "markdown", 185 | "metadata": {}, 186 | "source": [ 187 | "The output for the Hilbert series and quasipolynomial has to be read as follows: \n", 188 | "\n", 189 | "For the series, the first vector consists of the coefficients of the numerator polynomial, e.g., `[1,14,15]` is $1+14t+15t^2$. The second vector collects the exponents in the denominator. For example `[1,1,1,1]` represents $(1-t)(1-t)(1-t)(1-t)=(1-t)^4$ and `[1,2]` is $(1-t)(1-t^2)$. The last entry is the possible shift of the Hilbert series.\n", 190 | "\n", 191 | "The output of the quasipolynomial usually consists of a list of vectors which show the coefficients of the respective polynomial associated to the congruence class modulo the period of the quasipolynomial. In the above example it is a proper polynomial, so only one vector is listed. The last entry is the greatest common divisor of all denominators in these polynomials. " 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "metadata": { 197 | "deletable": true, 198 | "editable": true, 199 | "slideshow": { 200 | "slide_type": "subslide" 201 | } 202 | }, 203 | "source": [ 204 | "If you are only interested in the lattice points, you can compute them via the command `Deg1Elements()`. Note that the output now has the homogenizing variable as last coordinate." 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": 4, 210 | "metadata": { 211 | "collapsed": false, 212 | "deletable": true, 213 | "editable": true, 214 | "slideshow": { 215 | "slide_type": "fragment" 216 | } 217 | }, 218 | "outputs": [ 219 | { 220 | "name": "stdout", 221 | "output_type": "stream", 222 | "text": [ 223 | "18\n", 224 | "[[0, 0, 0, 1], [0, 0, 1, 1], [0, 0, 2, 1], [0, 0, 3, 1], [0, 0, 4, 1], [0, 0, 5, 1], [0, 1, 0, 1], [0, 1, 1, 1], [0, 1, 2, 1], [0, 1, 3, 1], [0, 2, 0, 1], [0, 2, 1, 1], [0, 3, 0, 1], [1, 0, 0, 1], [1, 0, 1, 1], [1, 0, 2, 1], [1, 1, 0, 1], [2, 0, 0, 1]]\n" 225 | ] 226 | } 227 | ], 228 | "source": [ 229 | "LP = poly.Deg1Elements()\n", 230 | "print(len(LP))\n", 231 | "print(LP)" 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "metadata": { 237 | "deletable": true, 238 | "editable": true 239 | }, 240 | "source": [ 241 | "If you would like to have a list of all already computed properties and data, you can use the `print_properties()` function." 242 | ] 243 | }, 244 | { 245 | "cell_type": "code", 246 | "execution_count": 5, 247 | "metadata": { 248 | "collapsed": false, 249 | "deletable": true, 250 | "editable": true 251 | }, 252 | "outputs": [ 253 | { 254 | "name": "stdout", 255 | "output_type": "stream", 256 | "text": [ 257 | "TriangulationGenerators:\n", 258 | "[[0, 0, 0, 1], [0, 0, 5, 1], [0, 3, 0, 1], [2, 0, 0, 1]]\n", 259 | "\n", 260 | "\n", 261 | "ExtremeRays:\n", 262 | "[[0, 0, 0, 1], [0, 0, 5, 1], [0, 3, 0, 1], [2, 0, 0, 1]]\n", 263 | "\n", 264 | "\n", 265 | "SupportHyperplanes:\n", 266 | "[[-15, -10, -6, 30], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]]\n", 267 | "\n", 268 | "\n", 269 | "HilbertBasis:\n", 270 | "[[0, 0, 0, 1], [0, 0, 1, 1], [0, 0, 2, 1], [0, 0, 3, 1], [0, 0, 4, 1], [0, 0, 5, 1], [0, 1, 0, 1], [0, 1, 1, 1], [0, 1, 2, 1], [0, 1, 3, 1], [0, 2, 0, 1], [0, 2, 1, 1], [0, 3, 0, 1], [1, 0, 0, 1], [1, 0, 1, 1], [1, 0, 2, 1], [1, 1, 0, 1], [2, 0, 0, 1], [1, 2, 4, 2]]\n", 271 | "\n", 272 | "\n", 273 | "Deg1Elements:\n", 274 | "[[0, 0, 0, 1], [0, 0, 1, 1], [0, 0, 2, 1], [0, 0, 3, 1], [0, 0, 4, 1], [0, 0, 5, 1], [0, 1, 0, 1], [0, 1, 1, 1], [0, 1, 2, 1], [0, 1, 3, 1], [0, 2, 0, 1], [0, 2, 1, 1], [0, 3, 0, 1], [1, 0, 0, 1], [1, 0, 1, 1], [1, 0, 2, 1], [1, 1, 0, 1], [2, 0, 0, 1]]\n", 275 | "\n", 276 | "\n", 277 | "Sublattice:\n", 278 | "[[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]], 1]\n", 279 | "\n", 280 | "\n", 281 | "OriginalMonoidGenerators:\n", 282 | "[[0, 0, 0, 1], [2, 0, 0, 1], [0, 3, 0, 1], [0, 0, 5, 1]]\n", 283 | "\n", 284 | "\n", 285 | "MaximalSubspace:\n", 286 | "[]\n", 287 | "\n", 288 | "\n", 289 | "Grading:\n", 290 | "[0, 0, 0, 1, 1]\n", 291 | "\n", 292 | "\n", 293 | "TriangulationSize:\n", 294 | "1\n", 295 | "\n", 296 | "\n", 297 | "TriangulationDetSum:\n", 298 | "30\n", 299 | "\n", 300 | "\n", 301 | "GradingDenom:\n", 302 | "1\n", 303 | "\n", 304 | "\n", 305 | "UnitGroupIndex:\n", 306 | "1\n", 307 | "\n", 308 | "\n", 309 | "InternalIndex:\n", 310 | "30\n", 311 | "\n", 312 | "\n", 313 | "Multiplicity:\n", 314 | "[30, 1]\n", 315 | "\n", 316 | "\n", 317 | "Rank:\n", 318 | "4\n", 319 | "\n", 320 | "\n", 321 | "EmbeddingDim:\n", 322 | "4\n", 323 | "\n", 324 | "\n", 325 | "IsPointed:\n", 326 | "True\n", 327 | "\n", 328 | "\n", 329 | "IsDeg1ExtremeRays:\n", 330 | "True\n", 331 | "\n", 332 | "\n", 333 | "IsDeg1HilbertBasis:\n", 334 | "False\n", 335 | "\n", 336 | "\n", 337 | "IsIntegrallyClosed:\n", 338 | "False\n", 339 | "\n", 340 | "\n", 341 | "IsInhomogeneous:\n", 342 | "False\n", 343 | "\n", 344 | "\n", 345 | "HilbertSeries:\n", 346 | "[[1, 14, 15], [1, 1, 1, 1], 0]\n", 347 | "\n", 348 | "\n", 349 | "HilbertQuasiPolynomial:\n", 350 | "[[1, 4, 8, 5], 1]\n", 351 | "\n", 352 | "\n", 353 | "IsTriangulationNested:\n", 354 | "False\n", 355 | "\n", 356 | "\n", 357 | "IsTriangulationPartial:\n", 358 | "False\n", 359 | "\n", 360 | "\n" 361 | ] 362 | } 363 | ], 364 | "source": [ 365 | "poly.print_properties()" 366 | ] 367 | }, 368 | { 369 | "cell_type": "markdown", 370 | "metadata": { 371 | "deletable": true, 372 | "editable": true, 373 | "slideshow": { 374 | "slide_type": "slide" 375 | } 376 | }, 377 | "source": [ 378 | "# Example 3: A rational polytope\n", 379 | "\n", 380 | "We construct a polytope with vertices $(5/2,3/2),(-2/3,-4/3),(1/4,-7/4)$.\n", 381 | "\n", 382 | "This is the first time we enter two different input types into the constructor. With the grading we declare the last coordinate to be the denominator of the vertices.\n" 383 | ] 384 | }, 385 | { 386 | "cell_type": "code", 387 | "execution_count": 6, 388 | "metadata": { 389 | "collapsed": false, 390 | "deletable": true, 391 | "editable": true, 392 | "slideshow": { 393 | "slide_type": "fragment" 394 | } 395 | }, 396 | "outputs": [ 397 | { 398 | "name": "stdout", 399 | "output_type": "stream", 400 | "text": [ 401 | "[[1, 1, 4, 4, 5, 2, 4, 6, 3, 2, 6, 4, 2, 3], [1, 1, 12], 0]\n", 402 | "[[24, 6, 47], [19, 6, 47], [16, 6, 47], [15, 6, 47], [40, 6, 47], [19, 6, 47], [0, 6, 47], [31, 6, 47], [40, 6, 47], [3, 6, 47], [16, 6, 47], [31, 6, 47], 24]\n" 403 | ] 404 | } 405 | ], 406 | "source": [ 407 | "rat_vert = [[5,3,2],[-2,-4,3],[1,-7,4]]\n", 408 | "g = [0,0,1]\n", 409 | "rat_poly = Cone(cone=rat_vert,grading=g)\n", 410 | "print(rat_poly.HilbertSeries())\n", 411 | "print(rat_poly.HilbertQuasiPolynomial())" 412 | ] 413 | }, 414 | { 415 | "cell_type": "markdown", 416 | "metadata": { 417 | "deletable": true, 418 | "editable": true, 419 | "slideshow": { 420 | "slide_type": "subslide" 421 | } 422 | }, 423 | "source": [ 424 | "We compute the integer hull of this polytope which is again a cone object and thus we can access its vertices or support hyperplanes." 425 | ] 426 | }, 427 | { 428 | "cell_type": "code", 429 | "execution_count": 13, 430 | "metadata": { 431 | "collapsed": false, 432 | "deletable": true, 433 | "editable": true, 434 | "slideshow": { 435 | "slide_type": "fragment" 436 | } 437 | }, 438 | "outputs": [ 439 | { 440 | "name": "stdout", 441 | "output_type": "stream", 442 | "text": [ 443 | "[[0, -1, 1], [2, 1, 1]]\n", 444 | "[[1, -2, 0], [1, 0, 0]]\n", 445 | "[[1, -1, -1]]\n" 446 | ] 447 | } 448 | ], 449 | "source": [ 450 | "int_hull = rat_poly.IntegerHull()\n", 451 | "print(int_hull.VerticesOfPolyhedron())\n", 452 | "print(int_hull.SupportHyperplanes())\n", 453 | "print(int_hull.Equations())" 454 | ] 455 | }, 456 | { 457 | "cell_type": "markdown", 458 | "metadata": { 459 | "deletable": true, 460 | "editable": true, 461 | "slideshow": { 462 | "slide_type": "slide" 463 | } 464 | }, 465 | "source": [ 466 | "# Example 4: A polyhedron\n", 467 | "\n", 468 | "We define a polyhedron by inequalties:\n", 469 | "$2x_2 \\geq -1$,\n", 470 | "$2x_2 \\leq 3$,\n", 471 | "$-2x_1+2x_2 \\leq 3$\n", 472 | "\n", 473 | "The input type is `inhom_inequalities` where a row $(a_1,\\ldots,a_n,b)$ in the input matrix defines the inequality\n", 474 | "\n", 475 | "\\begin{equation*}a_1x_1 +\\dots+a_nx_n+b\\geq0.\\end{equation*}\n", 476 | "\n", 477 | "In this case, `HilbertBasis()` returns the Hilbert basis of the recession cone associated to the polyhedron.\n" 478 | ] 479 | }, 480 | { 481 | "cell_type": "code", 482 | "execution_count": 8, 483 | "metadata": { 484 | "collapsed": false, 485 | "deletable": true, 486 | "editable": true, 487 | "slideshow": { 488 | "slide_type": "fragment" 489 | } 490 | }, 491 | "outputs": [ 492 | { 493 | "name": "stdout", 494 | "output_type": "stream", 495 | "text": [ 496 | "[[1, 0, 0]]\n", 497 | "[[-1, 0, 1], [0, 1, 1]]\n", 498 | "[[-4, -1, 2], [0, 3, 2]]\n" 499 | ] 500 | } 501 | ], 502 | "source": [ 503 | "ineq2 = [[0,2,1],[0,-2,3],[2,-2,3]]\n", 504 | "polyhedron = Cone(inhom_inequalities=ineq2)\n", 505 | "HB_rec = polyhedron.HilbertBasis()\n", 506 | "print(HB_rec)\n", 507 | "\n", 508 | "module_gen = polyhedron.ModuleGenerators()\n", 509 | "print(module_gen)\n", 510 | "\n", 511 | "vert_poly = polyhedron.VerticesOfPolyhedron()\n", 512 | "print(vert_poly)" 513 | ] 514 | }, 515 | { 516 | "cell_type": "markdown", 517 | "metadata": { 518 | "deletable": true, 519 | "editable": true, 520 | "slideshow": { 521 | "slide_type": "subslide" 522 | } 523 | }, 524 | "source": [ 525 | "We can also define the polyhedron via its generators, i.e. its vertices and generators of its recession cone.\n" 526 | ] 527 | }, 528 | { 529 | "cell_type": "code", 530 | "execution_count": 9, 531 | "metadata": { 532 | "collapsed": false, 533 | "deletable": true, 534 | "editable": true, 535 | "slideshow": { 536 | "slide_type": "fragment" 537 | } 538 | }, 539 | "outputs": [ 540 | { 541 | "name": "stdout", 542 | "output_type": "stream", 543 | "text": [ 544 | "[[-1, 0, 1], [0, 1, 1]]\n", 545 | "[[1, 0, 0]]\n" 546 | ] 547 | } 548 | ], 549 | "source": [ 550 | "poly2 = Cone(vertices=vert_poly,cone=[[1,0]])\n", 551 | "\n", 552 | "int_hull2 = poly2.IntegerHull()\n", 553 | "print(int_hull2.VerticesOfPolyhedron())\n", 554 | "print(int_hull2.ExtremeRays())" 555 | ] 556 | }, 557 | { 558 | "cell_type": "markdown", 559 | "metadata": { 560 | "collapsed": true, 561 | "deletable": true, 562 | "editable": true, 563 | "slideshow": { 564 | "slide_type": "slide" 565 | } 566 | }, 567 | "source": [ 568 | "# Creating new functions\n", 569 | "As an example for the usefulness of PyNormaliz we write a small function that creates the intersection of two cones - something which would be quite messy if we work with input files." 570 | ] 571 | }, 572 | { 573 | "cell_type": "code", 574 | "execution_count": 10, 575 | "metadata": { 576 | "collapsed": false, 577 | "deletable": true, 578 | "editable": true, 579 | "slideshow": { 580 | "slide_type": "fragment" 581 | } 582 | }, 583 | "outputs": [ 584 | { 585 | "name": "stdout", 586 | "output_type": "stream", 587 | "text": [ 588 | "[[1, 1], [1, 2]]\n" 589 | ] 590 | } 591 | ], 592 | "source": [ 593 | "def intersection(cone1, cone2):\n", 594 | " intersection_ineq = cone1.SupportHyperplanes()+cone2.SupportHyperplanes()\n", 595 | " C = Cone(inequalities = intersection_ineq)\n", 596 | " return C\n", 597 | "\n", 598 | "C1 = Cone(cone=[[1,2],[2,1]])\n", 599 | "C2 = Cone(cone=[[1,1],[1,3]])\n", 600 | "print(intersection(C1,C2).ExtremeRays())" 601 | ] 602 | }, 603 | { 604 | "cell_type": "code", 605 | "execution_count": 11, 606 | "metadata": { 607 | "collapsed": false, 608 | "deletable": true, 609 | "editable": true, 610 | "hideCode": true, 611 | "hideOutput": true, 612 | "hidePrompt": true 613 | }, 614 | "outputs": [ 615 | { 616 | "name": "stdout", 617 | "output_type": "stream", 618 | "text": [ 619 | "[1, 1, 1, -1, -1, -1, 0, 0, 0]\n", 620 | "[1, 1, 1, 0, 0, 0, -1, -1, -1]\n", 621 | "[0, 1, 1, -1, 0, 0, -1, 0, 0]\n", 622 | "[1, 0, 1, 0, -1, 0, 0, -1, 0]\n", 623 | "[1, 1, 0, 0, 0, -1, 0, 0, -1]\n", 624 | "[0, 1, 1, 0, -1, 0, 0, 0, -1]\n", 625 | "[1, 1, 0, 0, -1, 0, -1, 0, 0]\n" 626 | ] 627 | } 628 | ], 629 | "source": [ 630 | "def magic_square(n):\n", 631 | " equation = [1 if xmagic_square(n)\n", 675 | "generates all defining equations of the $n\\times n$ magic squares. \n", 676 | "\n", 677 | "So only a few lines of code are necessary to create the respective cone and compute its Hilbert basis (in the dual mode) and Hilbert series." 678 | ] 679 | }, 680 | { 681 | "cell_type": "code", 682 | "execution_count": 12, 683 | "metadata": { 684 | "collapsed": false, 685 | "deletable": true, 686 | "editable": true 687 | }, 688 | "outputs": [ 689 | { 690 | "name": "stdout", 691 | "output_type": "stream", 692 | "text": [ 693 | "20\n", 694 | "[[1, 4, 18, 36, 50, 36, 18, 4, 1], [1, 1, 1, 1, 2, 2, 2, 2], 0]\n" 695 | ] 696 | } 697 | ], 698 | "source": [ 699 | "n=4\n", 700 | "grading = [1 if x>> from PyNormaliz import Cone, NmzCone, NmzResult 5 | >>> V = [[-1, -1, 1], [-1, 0, 1], [-1, 1, 1], [0, -1, 1], [0, 0, 1], [0, 1, 1], [1, -1, 1], [1, 0, 1], [1, 1, 1]] 6 | >>> cube2 = NmzCone(vertices=V) 7 | >>> NmzResult(cube2,"Automorphisms") == [8, True, True, [[], []], [[[0, 2, 1, 3], [1, 0, 3, 2]], [[0, 1, 2, 3]]], [[[1, 0, 3, 2], [0, 2, 1, 3]], [[0, 1, 2, 3]]]] 8 | True 9 | 10 | -------------------------------------------------------------------------------- /tests/equation-41.txt: -------------------------------------------------------------------------------- 1 | Test equations 41 2 | =================== 3 | 4 | Equations error reported in https://github.com/Normaliz/PyNormaliz/issues/41 5 | 6 | >>> import PyNormaliz 7 | >>> cone = PyNormaliz.NmzCone(**{'inhom_inequalities': [[-1, 2, 0], [0, 0, 1], [2, -1, 0]], 'number_field': ['a^2 - 2', 'a', '[1.4 +/- 0.1]']}) 8 | >>> PyNormaliz.NmzResult(cone, "Equations") 9 | [] 10 | -------------------------------------------------------------------------------- /tests/generic_test.py: -------------------------------------------------------------------------------- 1 | #/usr/bin/env python 2 | # Test file for PyNormaliz module 3 | # 4 | # Just run 5 | # 6 | # $ python generic_test.py 7 | # 8 | # or alternatively from a Python console 9 | # 10 | # >>> import generic_test 11 | # >>> generic_test.Test1(verbose=True).run(repeat=50) 12 | 13 | from __future__ import print_function 14 | 15 | import unittest 16 | from sys import stdout 17 | 18 | from PyNormaliz import NmzCone, NmzResult, normaliz_error 19 | 20 | from itertools import product 21 | from random import shuffle 22 | 23 | methods = [ 24 | "AffineDim", 25 | "Automorphisms", 26 | "Congruences", 27 | "Dehomogenization", 28 | "Equations", 29 | "EmbeddingDim", 30 | # NOTE: floating point value 31 | # "EuclideanVolume", 32 | "EhrhartQuasiPolynomial", 33 | "ExcludedFaces", 34 | "ExternalIndex", 35 | "ExtremeRays", 36 | "GeneratorOfInterior", 37 | "Grading", 38 | "GradingDenom", 39 | "HilbertQuasiPolynomial", 40 | "InclusionExclusionData", 41 | "IsIntegrallyClosed", 42 | "IsInhomogeneous", 43 | "IsPointed", 44 | "IsTriangulationNested", 45 | "IsTriangulationPartial", 46 | "MaximalSubspace", 47 | "ModuleRank", 48 | "ModuleGenerators", 49 | "ReesPrimaryMultiplicity", 50 | "SupportHyperplanes", 51 | "Triangulation", 52 | "TriangulationSize", 53 | "UnitGroupIndex", 54 | "VerticesOfPolyhedron", 55 | "Volume", 56 | "Rank", 57 | "RecessionRank", 58 | # NOTE: depends on CoCoALib 59 | # "WeightedEhrhartQuasiPolynomial", 60 | "WitnessNotIntegrallyClosed", 61 | ] 62 | 63 | postprocess = { 64 | "VerticesOfPolyhedron": sorted, 65 | } 66 | 67 | class GenericPyNormalizTest: 68 | def __init__(self, verbosity=1): 69 | self.verbosity = verbosity 70 | 71 | def expected_answers(self): 72 | ans = {} 73 | for meth in methods: 74 | try: 75 | obj = getattr(self, meth) 76 | except AttributeError: 77 | continue 78 | else: 79 | ans[meth] = obj 80 | return ans 81 | 82 | def run(self, repeat=1): 83 | tested = failed = 0 84 | if self.verbosity >= 1: 85 | print("Unittest {} ({} repetitions)".format(self, repeat)) 86 | 87 | ans = self.expected_answers() 88 | def_methods = sorted(ans.keys()) 89 | 90 | if self.verbosity >= 2: 91 | undef_methods = sorted(set(methods).difference(def_methods)) 92 | print("Testing: {}".format(", ".join(meth for meth in def_methods))) 93 | print("Skipping: {}".format(", ".join(meth for meth in undef_methods))) 94 | 95 | for i in range(repeat): 96 | if self.verbosity >= 3: 97 | print("*"*80) 98 | print("{} run {}".format(self, i)) 99 | stdout.flush() 100 | polytope = NmzCone(**self.init_data) 101 | 102 | shuffle(def_methods) 103 | for meth in def_methods: 104 | tested += 1 105 | 106 | obj = ans[meth] 107 | if self.verbosity >= 3: 108 | print("Testing {}... ".format(meth), end='') 109 | stdout.flush() 110 | 111 | # if we expect an exception we just check that calling 112 | # the method indeed raises exception 113 | if type(obj) is type and issubclass(obj, Exception): 114 | try: 115 | NmzResult(polytope, meth) 116 | except obj: 117 | if self.verbosity >= 3: 118 | print("pass") 119 | stdout.flush() 120 | continue 121 | except Exception as obj2: 122 | print("*"*50) 123 | print("Unittest {}, failure {}".format(self, meth)) 124 | print("{}: got {} instead of {}".format(meth, obj2, obj)) 125 | print("*"*50) 126 | stdout.flush() 127 | failed += 1 128 | 129 | # otherwise we just check equality of results 130 | # (possibly after some postprocessing) 131 | else: 132 | obj2 = NmzResult(polytope, meth) 133 | post = postprocess.get(meth) 134 | if post is not None: 135 | obj = post(obj) 136 | obj2 = post(obj2) 137 | 138 | if obj != obj2: 139 | print("*"*50) 140 | print("Unittest {}, failure {}".format(self, meth)) 141 | print("{}: got {} instead of {}".format(meth, obj2, obj)) 142 | print("*"*50) 143 | stdout.flush() 144 | failed += 1 145 | elif self.verbosity >= 3: 146 | print("pass") 147 | stdout.flush() 148 | 149 | return failed 150 | 151 | class Test1(GenericPyNormalizTest): 152 | init_data = {"vertices": [(-3,-2,-1,1), (-1,1,-1,2), (1,1,-1,1), (1,1,1,1)]} 153 | 154 | # expected results 155 | AffineDim = 3 156 | Congruences = [] 157 | Dehomogenization = [0,0,0,1] 158 | EhrhartQuasiPolynomial = [[6,7,6,5], 6] 159 | Equations = [] 160 | EmbeddingDim = 4 161 | ExcludedFaces = normaliz_error 162 | ExternalIndex = normaliz_error 163 | ExtremeRays = [] 164 | GeneratorOfInterior = normaliz_error 165 | Grading = normaliz_error 166 | GradingDenom = normaliz_error 167 | HilbertQuasiPolynomial = normaliz_error 168 | InclusionExclusionData = normaliz_error 169 | IsIntegrallyClosed = normaliz_error 170 | IsInhomogeneous = True 171 | IsPointed = True 172 | IsTriangulationPartial = Exception # what is the actual error we got here? 173 | IsTriangulationNested = Exception # idem 174 | MaximalSubspace = [] 175 | ModuleRank = 4 176 | ModuleGenerators = [[-3,-2,-1,1], [1,1,-1,1], [1,1,0,1], [1,1,1,1]] 177 | Rank = 4 178 | RecessionRank = 0 179 | ReesPrimaryMultiplicity = normaliz_error 180 | SupportHyperplanes = [[-3,4,0,-1], [1,-3,0,2], [3,-4,5,6], [7,-6,-5,4]] 181 | Triangulation = [[[[0, 1, 2, 3], 10, []]], [[-3, -2, -1, 1], [-1, 1, -1, 2], [1, 1, -1, 1], [1, 1, 1, 1]]] 182 | TriangulationSize = 1 183 | UnitGroupIndex = normaliz_error 184 | VerticesOfPolyhedron = [[-3,-2,-1,1], [-1,1,-1,2], [1,1,-1,1], [1,1,1,1]] 185 | Volume = [5,1] 186 | WitnessNotIntegrallyClosed = normaliz_error 187 | 188 | class Test2(GenericPyNormalizTest): 189 | "A cube in a subspace" 190 | 191 | init_data = {"vertices": list((2,) + p+(-2,1,) for p in product([-1,0,1],repeat=2))} 192 | 193 | # expected results 194 | AffineDim = 2 195 | Automorphisms = [8, True, True, [[], []], [[[0, 2, 1, 3], [1, 0, 3, 2]], [[0, 1, 2, 3]]], [[[1, 0, 3, 2], [0, 2, 1, 3]], [[0, 1, 2, 3]]]] 196 | Congruences = [] 197 | Dehomogenization = normaliz_error 198 | EmbeddingDim = 5 199 | EhrhartQuasiPolynomial = [[1,4,4],1] 200 | Equations = [[1,0,0,0,-2],[0,0,0,1,2]] 201 | ExcludedFaces = normaliz_error 202 | ExternalIndex = 1 203 | ExtremeRays = [] 204 | GeneratorOfInterior = normaliz_error 205 | Grading = normaliz_error 206 | GradingDenom = normaliz_error 207 | HilbertQuasiPolynomial = normaliz_error 208 | InclusionExclusionData = normaliz_error 209 | IsInhomogeneous = True 210 | IsIntegrallyClosed = normaliz_error 211 | IsPointed = True 212 | IsTriangulationPartial = Exception # what is the actual error we got here? 213 | IsTriangulationNested = Exception # idem 214 | MaximalSubspace = [] 215 | ModuleGenerators = [[2,-1,-1,-2,1], [2,-1,0,-2,1], [2,-1,1,-2,1], [2,0,-1,-2,1], 216 | [2,0,0,-2,1], [2,0,1,-2,1], [2,1,-1,-2,1], [2,1,0,-2,1], [2,1,1,-2,1]] 217 | ModuleRank = 9 218 | Rank = 3 219 | ReesPrimaryMultiplicity = normaliz_error 220 | RecessionRank = 0 221 | SupportHyperplanes = [[0,-1,0,0,1],[0,0,-1,0,1],[0,0,1,0,1],[0,1,0,0,1]] 222 | Triangulation = [[[[0, 1, 3], 1, []], [[1, 2, 3], 1, []], [[2, 3, 4], 1, []], [[2, 4, 5], 1, []], [[3, 4, 6], 1, []], [[4, 5, 6], 1, []], [[5, 6, 7], 1, []], [[5, 7, 8], 1, []]], [[2, -1, -1, -2, 1], [2, -1, 0, -2, 1], [2, -1, 1, -2, 1], [2, 0, -1, -2, 1], [2, 0, 0, -2, 1], [2, 0, 1, -2, 1], [2, 1, -1, -2, 1], [2, 1, 0, -2, 1], [2, 1, 1, -2, 1]]] 223 | TriangulationSize = 8 224 | UnitGroupIndex = normaliz_error 225 | VerticesOfPolyhedron = [[2,-1,-1,-2,1], [2,-1,1,-2,1], [2,1,-1,-2,1], [2,1,1,-2,1]] 226 | Volume = [8,1] 227 | WitnessNotIntegrallyClosed = normaliz_error 228 | 229 | class Test3(GenericPyNormalizTest): 230 | "A 2-dimensional linear subspace" 231 | 232 | init_data = {"vertices": [[1,2,3,5]], "cone": [[1,0,-1],[-1,0,1]]} 233 | 234 | # expected results 235 | AffineDim = 1 236 | Congruences = [] 237 | Dehomogenization = normaliz_error 238 | EmbeddingDim = 4 239 | EhrhartQuasiPolynomial = [[1], [0], [0], [0], [0], 1] 240 | Equations = [[1,-2,1,0],[0,5,0,-2]] 241 | # Generators = ... 242 | # apparently not well defined -- and therefore no longer in use 243 | Grading = normaliz_error 244 | HilbertQuasiPolynomial = normaliz_error 245 | IsInhomogeneous = True 246 | IsIntegrallyClosed = normaliz_error 247 | IsPointed = False 248 | VerticesOfPolyhedron = [[0,2,4,5]] 249 | ExtremeRays = [] 250 | MaximalSubspace = [[1,0,-1,0]] 251 | ModuleGenerators = [] 252 | ModuleRank = 0 253 | # SupportHyperplanes = [[0,0,0,1]] # [[0,-2,0,1]] 254 | # not well defined 255 | RecessionRank = 1 256 | TriangulationSize = 1 257 | Volume = normaliz_error 258 | WitnessNotIntegrallyClosed = normaliz_error 259 | 260 | 261 | class Test4(GenericPyNormalizTest): 262 | init_data = {"vertices": [[0,0,1],[1,0,1],[0,1,1]], "cone": [[1, 1]]} 263 | 264 | # expected results 265 | Equations = [] 266 | ExtremeRays = [[1,1,0]] 267 | MaximalSubspace = [] 268 | ModuleGenerators = [[0,0,1],[0,1,1],[1,0,1]] 269 | SupportHyperplanes = [[-1,1,1],[0,1,0],[1,-1,1],[1,0,0]] 270 | VerticesOfPolyhedron = [[0,0,1],[0,1,1],[1,0,1]] 271 | Volume = normaliz_error 272 | 273 | tests = [Test1, Test2, Test3, Test4] 274 | 275 | if __name__ == '__main__': 276 | for test in tests: 277 | test().run() 278 | -------------------------------------------------------------------------------- /tests/modify_cone.txt: -------------------------------------------------------------------------------- 1 | Test modify cone 2 | ================== 3 | 4 | >>> from PyNormaliz import NmzCone, NmzResult, NmzModifyCone 5 | >>> C = NmzCone(cone=[[1,0],[0,1]]) 6 | >>> NmzResult(C,"HilbertBasis") == [[0, 1], [1, 0]] 7 | True 8 | >>> NmzModifyCone(C,"cone",[[-1,0]]) 9 | True 10 | >>> NmzResult(C,"HilbertBasis") == [[0, 1]] 11 | True -------------------------------------------------------------------------------- /tests/modify_cone_renf.txt: -------------------------------------------------------------------------------- 1 | Test modify cone renf 2 | ================== 3 | 4 | >>> from PyNormaliz import NmzCone, NmzResult, NmzModifyCone 5 | >>> nf = [ "a4-5a2+5", "a", "1.9021+/-0.01" ] 6 | >>> C = NmzCone(number_field=nf, cone=[[1,0],[0,1]]) 7 | >>> NmzResult(C,"ExtremeRays") == [[[[0, 1]], [[1, 1]]], [[[1, 1]], [[0, 1]]]] 8 | True 9 | >>> NmzModifyCone(C,"cone",[[-1,0]]) 10 | True 11 | >>> NmzResult(C,"ExtremeRays") == [[[[0, 1]], [[1, 1]]]] 12 | True -------------------------------------------------------------------------------- /tests/must_be_matrices-39.txt: -------------------------------------------------------------------------------- 1 | Test entries must be matrices 39 2 | ===================================== 3 | 4 | Bug reported in https://github.com/Normaliz/PyNormaliz/issues/39 5 | 6 | >>> import PyNormaliz 7 | >>> p = PyNormaliz.NmzCone(cone=[[1, 1]], subspace=[[-1, 1]], vertices=[[3, 2, 6]]) 8 | -------------------------------------------------------------------------------- /tests/quasi_poly-36.txt: -------------------------------------------------------------------------------- 1 | Interface error on quasi-polynomial 36 2 | ======================================== 3 | 4 | Bug reported in https://github.com/Normaliz/PyNormaliz/issues/36 5 | 6 | >>> import PyNormaliz 7 | >>> cube = PyNormaliz.NmzCone(vertices = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 0, 1], [0, 1, 1, 1], [1, 0, 0, 1], [1, 0, 1, 1], [1, 1, 0, 1], [1, 1, 1, 1]]) 8 | >>> PyNormaliz.NmzCompute(cube, "EhrhartSeries" ) 9 | True 10 | >>> PyNormaliz.NmzResult(cube, "EhrhartQuasiPolynomial") == [[1, 3, 3, 1], 1] 11 | True 12 | -------------------------------------------------------------------------------- /tests/rational.txt: -------------------------------------------------------------------------------- 1 | Rational 2 | ================ 3 | 4 | Based on rational.in in Normaliz resp. rational.tst in NormalizInterface 5 | 6 | >>> import PyNormaliz 7 | >>> M = [[1,1,2 ],[-1,-1,3],[1,-2,4]] 8 | >>> gr = [[0,0,1]] 9 | >>> cone = PyNormaliz.Cone(integral_closure=M, grading=gr) 10 | >>> cone.HilbertBasis() == [[0, 0, 1], [1, 1, 2], [-1, -1, 3], [0, -1, 3], [1, 0, 3], [1, -2, 4], [1, -1, 4], [0, -2, 5]] 11 | True 12 | >>> cone.HilbertSeries() == [[1, 0, 0, 3, 2, -1, 2, 2, 1, 1, 1, 1, 2], [1, 2, 12], 0] 13 | True 14 | -------------------------------------------------------------------------------- /tests/runtests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | ############################################################################### 3 | # Test script for PyNormaliz # 4 | ############################################################################### 5 | from __future__ import print_function, division 6 | 7 | import sys 8 | import os 9 | import glob 10 | import doctest 11 | 12 | # some doctest are conditional on the presence of some libraries 13 | # and normaliz configuration 14 | import PyNormaliz 15 | skip = set() 16 | if not PyNormaliz.NmzHasEAntic(): 17 | skip.add("equation-41.txt") 18 | skip.add("segfault-27.txt") 19 | skip.add("segfault-35.txt") 20 | skip.add("vertex_denom-37.txt") 21 | skip.add("modify_cone_renf.txt") 22 | 23 | if not PyNormaliz.NmzHasCocoa(): 24 | skip.add("test_rational_cones.txt") 25 | 26 | # run doctests 27 | attempted = failed = 0 28 | dir = os.path.dirname(os.path.realpath(__file__)) 29 | for filename in os.listdir(dir): 30 | if filename.endswith('.txt'): 31 | if filename in skip: 32 | print("Skip {}".format(filename)) 33 | continue 34 | 35 | print("Doctest {}".format(filename)) 36 | result = doctest.testfile(filename, 37 | optionflags=doctest.IGNORE_EXCEPTION_DETAIL | 38 | doctest.NORMALIZE_WHITESPACE | 39 | doctest.REPORT_NDIFF) 40 | print(" {} tests".format(result[1])) 41 | if result[0]: 42 | print(" {} FAILURES".format(result[0])) 43 | failed += result[0] 44 | attempted += result[1] 45 | 46 | 47 | # unit tests 48 | from generic_test import tests 49 | 50 | for test in tests: 51 | failed += test(verbosity=2).run(repeat=10) 52 | 53 | sys.exit(failed) 54 | -------------------------------------------------------------------------------- /tests/segfault-23.txt: -------------------------------------------------------------------------------- 1 | Test segfault 23 2 | ================ 3 | 4 | Segfault reported in https://github.com/Normaliz/PyNormaliz/issues/23 5 | 6 | >>> from PyNormaliz import Cone, NmzCone, NmzResult 7 | >>> V = [[-1, -1, 1], [-1, 0, 1], [-1, 1, 1], [0, -1, 1], [0, 0, 1], [0, 1, 1], [1, -1, 1], [1, 0, 1], [1, 1, 1]] 8 | >>> cube1 = Cone(vertices=V) 9 | >>> cube2 = NmzCone(vertices=V) 10 | >>> NmzResult(cube2, "SupportHyperplanes") == [[-1, 0, 1], [0, -1, 1], [0, 1, 1], [1, 0, 1]] 11 | True 12 | >>> NmzResult(cube2, "Volume") == [8,1] 13 | True 14 | >>> len(cube1.Triangulation()[0]) == 8 15 | True 16 | -------------------------------------------------------------------------------- /tests/segfault-27.txt: -------------------------------------------------------------------------------- 1 | Test segfault 27 2 | ================ 3 | 4 | Segfault reported in https://github.com/Normaliz/PyNormaliz/issues/27 5 | 6 | >>> import PyNormaliz 7 | >>> nf = [ "a4-5a2+5", "a", "1.9021+/-0.01" ] 8 | >>> C = PyNormaliz.NmzCone(number_field=nf, cone=[[[1],[0,1]],[[1],[-1]]]) 9 | >>> PyNormaliz.NmzResult(C, "ExtremeRays") == [[[[0, 1], [1, 1], [0, 1], [-1, 5]], [[1, 1], [0, 1], [0, 1], [0, 1]]], [[[1, 1], [0, 1], [0, 1], [0, 1]], [[-1, 1], [0, 1], [0, 1], [0, 1]]]] 10 | True 11 | -------------------------------------------------------------------------------- /tests/segfault-35.txt: -------------------------------------------------------------------------------- 1 | Test segfault 35 2 | ================ 3 | 4 | Segfault reported in https://github.com/Normaliz/PyNormaliz/issues/35 5 | 6 | >>> import PyNormaliz 7 | >>> p = PyNormaliz.NmzCone(cone=[], number_field=[ "a^2 - 2", "a", "1.414213562373095 +/- 2.99e-16" ], subspace=[], vertices=[[1, 1], [[[0, 1], [1, 1]], 1]]) 8 | -------------------------------------------------------------------------------- /tests/segfault-45.txt: -------------------------------------------------------------------------------- 1 | Test segfault 45 2 | ================ 3 | 4 | Segfault reported in https://github.com/Normaliz/PyNormaliz/issues/45 5 | 6 | >>> from PyNormaliz import NmzCone, NmzResult 7 | >>> polytope = NmzCone(vertices=[(-3,-2,-1,1), (-1,1,-1,2), (1,1,-1,1), (1,1,1,1)]) 8 | >>> NmzResult(polytope, "EhrhartQuasiPolynomial") == [[6, 7, 6, 5], 6] 9 | True 10 | -------------------------------------------------------------------------------- /tests/test_rational_cones.txt: -------------------------------------------------------------------------------- 1 | Test rational cone 2 | ================== 3 | 4 | The cube 5 | 6 | >>> from PyNormaliz import Cone, NmzCone, NmzResult 7 | >>> from itertools import product 8 | >>> V = list(list(p+(1,)) for p in product([-1,0,1],repeat=2)) 9 | >>> cube1 = Cone(vertices=V) 10 | >>> cube2 = NmzCone(vertices=V) 11 | >>> verts = cube1.VerticesOfPolyhedron() 12 | >>> verts == NmzResult(cube2, "VerticesOfPolyhedron") 13 | True 14 | >>> verts == [[-1, -1, 1], [-1, 1, 1], [1, -1, 1], [1, 1, 1]] 15 | True 16 | >>> rays = cube1.ExtremeRays() 17 | >>> rays == NmzResult(cube2, "ExtremeRays") == [] 18 | True 19 | >>> cube1.MaximalSubspace() == NmzResult(cube2, "MaximalSubspace") == [] 20 | True 21 | >>> hyperplanes = cube1.SupportHyperplanes() 22 | >>> hyperplanes == NmzResult(cube2, "SupportHyperplanes") 23 | True 24 | >>> hyperplanes == [[-1, 0, 1], [0, -1, 1], [0, 1, 1], [1, 0, 1]] 25 | True 26 | >>> cube1.Equations() == NmzResult(cube2, "Equations") == [] 27 | True 28 | >>> cube1.Congruences() == NmzResult(cube2, "Congruences") == [] 29 | True 30 | >>> cube1.AffineDim() == NmzResult(cube2, "AffineDim") == 2 31 | True 32 | >>> cube1.Volume() == 8 33 | True 34 | >>> NmzResult(cube2, "Volume") == [8,1] 35 | True 36 | >>> cube1.IsPointed() == NmzResult(cube2, "IsPointed") == True 37 | True 38 | >>> cube1.EmbeddingDim() == NmzResult(cube2, "EmbeddingDim") == 3 39 | True 40 | >>> cube1.IsIntegrallyClosed() 41 | Traceback (most recent call last): 42 | ... 43 | NormalizError: ... 44 | >>> NmzResult(cube2, "IsIntegrallyClosed") 45 | Traceback (most recent call last): 46 | ... 47 | NormalizError: ... 48 | >>> cube1.EuclideanVolume() == '4.0000' 49 | True 50 | >>> abs(NmzResult(cube2, "EuclideanVolume") - 4) < 0.000001 51 | True 52 | >>> len(cube1.Triangulation()[0]) == len(NmzResult(cube2, "Triangulation")[0]) == 8 53 | True 54 | >>> int_pts = [[-1,-1,1],[-1,0,1],[-1,1,1],[0,-1,1],[0,0,1],[0,1,1],[1,-1,1],[1,0,1],[1,1,1]] 55 | >>> cube1.ModuleGenerators() == NmzResult(cube2, "ModuleGenerators") == int_pts 56 | True 57 | >>> cube1.Rank() == NmzResult(cube2, "Rank") == 3 58 | True 59 | >>> cube1.ModuleRank() == NmzResult(cube2, "ModuleRank") == 9 60 | True 61 | >>> sublattice = [[[1,0,0],[0,1,0],[0,0,1]],[[1,0,0],[0,1,0],[0,0,1]],1] 62 | >>> cube1.Sublattice() == NmzResult(cube2, "Sublattice") == sublattice 63 | True 64 | >>> cube1.TriangulationSize() == NmzResult(cube2, "TriangulationSize") == 8 65 | True 66 | >>> NmzResult(cube2, "FVector" ) == [ 1, 4, 4, 1 ] 67 | True 68 | >>> len(NmzResult(cube2, "FaceLattice")) == 10 69 | True 70 | >>> cube1.Automorphisms() == [8, True, True, [[], []], [[[0, 2, 1, 3], [1, 0, 3, 2]], [[0, 1, 2, 3]]], [[[1, 0, 3, 2], [0, 2, 1, 3]], [[0, 1, 2, 3]]]] 71 | True 72 | >>> cube1.CombinatorialAutomorphisms() == [8, False, False, [[], []], [[[0, 2, 1, 3], [1, 0, 3, 2]], [[0, 1, 2, 3]]], [[[1, 0, 3, 2], [0, 2, 1, 3]], [[0, 1, 2, 3]]]] 73 | True 74 | >>> cube1.RationalAutomorphisms() == [8, True, True, [[], []], [[[0, 2, 1, 3], [1, 0, 3, 2]], [[0, 1, 2, 3]]], [[[1, 0, 3, 2], [0, 2, 1, 3]], [[0, 1, 2, 3]]]] 75 | True 76 | >>> cube1.RationalAutomorphisms() == [8, True, True, [[], []], [[[0, 2, 1, 3], [1, 0, 3, 2]], [[0, 1, 2, 3]]], [[[1, 0, 3, 2], [0, 2, 1, 3]], [[0, 1, 2, 3]]]] 77 | True 78 | >>> cube1.EuclideanAutomorphisms() == [8, False, False, [[], []], [[[0, 2, 1, 3], [1, 0, 3, 2]], [[0, 1, 2, 3]]], [[[1, 0, 3, 2], [0, 2, 1, 3]], [[0, 1, 2, 3]]]] 79 | True 80 | >>> cube1.Incidence() == [[0, 0, 1, 1], [0, 1, 0, 1], [1, 0, 1, 0], [1, 1, 0, 0]] 81 | True 82 | >>> len(NmzResult(cube2, "DualFaceLattice")) == 10 83 | True 84 | >>> NmzResult(cube2, "DualFVector" ) == [ 1, 4, 4, 1 ] 85 | True 86 | >>> cube1.UnimodularTriangulation() == [[[[0, 1, 3], 1, []], [[1, 2, 3], 1, []], [[2, 3, 4], 1, []], [[2, 4, 5], 1, []], [[3, 4, 6], 1, []], [[4, 5, 6], 1, []], [[5, 6, 7], 1, []], [[5, 7, 8], 1, []]], [[-1, -1, 1], [-1, 0, 1], [-1, 1, 1], [0, -1, 1], [0, 0, 1], [0, 1, 1], [1, -1, 1], [1, 0, 1], [1, 1, 1]]] 87 | True 88 | >>> cube1.AllGeneratorsTriangulation() == [[[[0, 1, 3], 1, []], [[1, 2, 3], 1, []], [[2, 3, 4], 1, []], [[2, 4, 5], 1, []], [[3, 4, 6], 1, []], [[4, 5, 6], 1, []], [[5, 6, 7], 1, []], [[5, 7, 8], 1, []]], [[-1, -1, 1], [-1, 0, 1], [-1, 1, 1], [0, -1, 1], [0, 0, 1], [0, 1, 1], [1, -1, 1], [1, 0, 1], [1, 1, 1]]] 89 | True 90 | >>> cube1.LatticePointTriangulation() == [[[[0, 1, 3], 1, []], [[1, 2, 3], 1, []], [[2, 3, 4], 1, []], [[2, 4, 5], 1, []], [[3, 4, 6], 1, []], [[4, 5, 6], 1, []], [[5, 6, 7], 1, []], [[5, 7, 8], 1, []]], [[-1, -1, 1], [-1, 0, 1], [-1, 1, 1], [0, -1, 1], [0, 0, 1], [0, 1, 1], [1, -1, 1], [1, 0, 1], [1, 1, 1]]] 91 | True 92 | >>> cube1.SetPolynomial("x[1] + x[2] +1") == True 93 | True 94 | >>> cube1.Polynomial() == 'x[1] + x[2] +1' 95 | True 96 | >>> cube1.Integral() == 4 97 | True 98 | >>> cube1.EuclideanIntegral() == '4.0000' 99 | True 100 | >>> cube1.VirtualMultiplicity() == 0 101 | True 102 | >>> cube1.WeightedEhrhartSeries() == [[1, 6, 1], [1, 1, 1], 0, 1] 103 | True 104 | >>> cube1.EhrhartSeries() == [[1, 6, 1], [1, 1, 1], 0] 105 | True 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /tests/vertex_denom-37.txt: -------------------------------------------------------------------------------- 1 | Test segfault 37 2 | ================ 3 | 4 | Segfault reported in https://github.com/Normaliz/PyNormaliz/issues/37 5 | 6 | >>> import PyNormaliz 7 | >>> p = PyNormaliz.NmzCone(cone=[], number_field=['a^2 - 2', 'a', '[1.414213562373095 +/- 2.99e-16]'], subspace=[], vertices=[[1, 1], [[[0, 1], [1, 1]], 1]]) 8 | -------------------------------------------------------------------------------- /tests/volume_20.txt: -------------------------------------------------------------------------------- 1 | Test volume 20 2 | ================ 3 | 4 | Volume error reported in https://github.com/Normaliz/PyNormaliz/issues/20 5 | 6 | >>> import PyNormaliz_cpp 7 | >>> cone = PyNormaliz_cpp.NmzCone(**{'subspace': [], 'vertices': [[0, 0, 0, 1], 8 | ... [0, 0, 1, 1], [0, 1, 0, 1], [0, 1, 1, 1], [1, 0, 0, 1], [1, 0, 1, 1], [1, 1, 0, 9 | ... 1], [1, 1, 1, 1]], 'cone': []}) 10 | >>> PyNormaliz_cpp.NmzResult(cone,'EuclideanVolume') - 1.0 < 0.01 11 | True 12 | -------------------------------------------------------------------------------- /tests/volume_22.txt: -------------------------------------------------------------------------------- 1 | Test volume 22 2 | ================ 3 | 4 | Volume error reported in https://github.com/Normaliz/PyNormaliz/issues/22 5 | 6 | >>> import PyNormaliz 7 | >>> square = PyNormaliz.Cone(vertices=[[0,0,1],[1,0,1],[0,1,1],[1,1,1]]) 8 | >>> square.EuclideanVolume() == '1.0000' 9 | True 10 | --------------------------------------------------------------------------------