pax_global_header00006660000000000000000000000064152117317510014515gustar00rootroot0000000000000052 comment=b8a3d6a6963a802c1b32207b76fa7528993d24e1 iqtree-piqtree-b8a3d6a/000077500000000000000000000000001521173175100151475ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/.devcontainer/000077500000000000000000000000001521173175100177065ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/.devcontainer/DockerFile000066400000000000000000000032601521173175100216410ustar00rootroot00000000000000FROM continuumio/miniconda3 # Install dependencies RUN apt-get update && apt-get install -y \ build-essential \ btop \ cmake \ gdb \ gh \ git \ zsh \ sudo \ wget \ libeigen3-dev \ libboost-all-dev \ binutils \ && rm -rf /var/lib/apt/lists/* # Set up a non-root user with sudo RUN useradd -ms /bin/zsh user && echo "user ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/user USER user WORKDIR /home/user/repos # Install Oh My Zsh RUN sh -c "$(wget https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh -O -)" "" --unattended # Install zsh autosuggestions RUN git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions # Install zsh syntax highlighting RUN git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting # Configure zsh RUN sed -i 's/plugins=(git)/plugins=(git zsh-autosuggestions zsh-syntax-highlighting)/' ~/.zshrc # Create a new conda environment with Python 3.14 and fix the bug with VS-code terminal showing 2 conda env prompts RUN . /opt/conda/etc/profile.d/conda.sh && \ conda config --set auto_activate_base False && \ /opt/conda/bin/conda create -n piq-dev python=3.14 -y && \ conda activate piq-dev # Initialize conda for zsh shell RUN echo ". /opt/conda/etc/profile.d/conda.sh" >> ~/.zshrc # Install pybind11 in the conda environment RUN . /opt/conda/etc/profile.d/conda.sh && \ conda activate piq-dev && \ pip install pybind11 # Set up zsh as the default shell SHELL ["/bin/zsh", "-c"] # Set zsh as the default shell for the container CMD [ "zsh" ]iqtree-piqtree-b8a3d6a/.devcontainer/devcontainer.json000066400000000000000000000027351521173175100232710ustar00rootroot00000000000000{ "name": "piqtree devcontainer", "image": "ghcr.io/iqtree/piqtree:latest", "customizations": { "vscode": { "settings": { "terminal.integrated.shell.linux": "/bin/zsh", "terminal.integrated.profiles.linux": { "zsh": { "path": "zsh" } }, "python.defaultInterpreterPath": "/home/user/.conda/envs/piq-dev/bin/python", "C_Cpp.default.includePath": [ "${workspaceFolder}/**", "/home/user/.conda/envs/piq-dev/lib/python3.14/site-packages/pybind11/include/", "/home/user/.conda/envs/piq-dev/include/python3.14/" ] }, "extensions": [ "ms-python.python", "ms-toolsai.jupyter", "ms-vscode.cpptools", "ms-vscode.cpptools-extension-pack", "ms-vscode.makefile-tools", "charliermarsh.ruff", "njpwerner.autodocstring", "github.vscode-github-actions", "tamasfe.even-better-toml", "DavidAnson.vscode-markdownlint", "be5invis.toml", "mhutchie.git-graph" ] } }, "remoteUser": "user", "postCreateCommand": "sudo chown -R user:user /home/user/.ssh && git config --global --add safe.directory ${containerWorkspaceFolder}" }iqtree-piqtree-b8a3d6a/.github/000077500000000000000000000000001521173175100165075ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/.github/actions/000077500000000000000000000000001521173175100201475ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/.github/actions/build-iqtree/000077500000000000000000000000001521173175100225355ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/.github/actions/build-iqtree/action.yml000066400000000000000000000054501521173175100245410ustar00rootroot00000000000000name: Fetch or Build IQ-TREE Static Library description: "Checks if the IQ-TREE static library exists, if not then building it." inputs: os: description: "Runner OS Name." required: true outputs: iqtree-sha: description: "SHA for commit of IQ-TREE static library." value: ${{ steps.iqtree-sha.outputs.iqtree-sha }} runs: using: composite steps: - id: iqtree-sha name: Get IQ-TREE SHA shell: bash run: | cd iqtree3 IQ_TREE_SHA=$(git rev-parse HEAD) echo "iqtree-sha=${IQ_TREE_SHA}" >> "$GITHUB_OUTPUT" - name: Cache IQ-TREE (Windows) if: runner.os == 'Windows' uses: actions/cache@v5 id: cache-windows with: key: libiqtree-${{ inputs.os }}-${{ steps.iqtree-sha.outputs.iqtree-sha }} path: | src/piqtree/_libiqtree/iqtree.lib src/piqtree/_libiqtree/iqtree.dll lookup-only: true - name: Cache IQ-TREE (Linux/macOS) if: runner.os != 'Windows' uses: actions/cache@v5 id: cache-unix with: key: libiqtree-${{ inputs.os }}-${{ steps.iqtree-sha.outputs.iqtree-sha }} path: | src/piqtree/_libiqtree/libiqtree.a lookup-only: true - name: Combine Cache Hits id: cache shell: bash run: | if [[ "${{ steps.cache-windows.outputs.cache-hit }}" == 'true' || "${{ steps.cache-unix.outputs.cache-hit }}" == 'true' ]]; then echo "cache-hit=true" >> "$GITHUB_OUTPUT" else echo "cache-hit=false" >> "$GITHUB_OUTPUT" fi - name: Install Boost if: runner.os == 'Windows' && steps.cache.outputs.cache-hit != 'true' uses: MarkusJx/install-boost@v2.6.0 id: install-boost with: boost_version: 1.84.0 platform_version: 2022 toolset: mingw - name: Set Boost Environment Variables if: runner.os == 'Windows' && steps.cache.outputs.cache-hit != 'true' shell: bash run: | echo "Boost_INCLUDE_DIR=${{ steps.install-boost.outputs.BOOST_ROOT }}/include" >> "$GITHUB_ENV" echo "Boost_LIBRARY_DIRS=${{ steps.install-boost.outputs.BOOST_ROOT }}/lib" >> "$GITHUB_ENV" - name: Setup MSVC Developer Command Prompt if: runner.os == 'Windows' && steps.cache.outputs.cache-hit != 'true' uses: ilammy/msvc-dev-cmd@v1 - name: Build IQ-TREE shell: bash if: steps.cache.outputs.cache-hit != 'true' run: | if [[ "${{ runner.os }}" == "Linux" ]]; then sudo ./build_tools/before_all_linux.sh elif [[ "${{ runner.os }}" == "macOS" ]]; then ./build_tools/before_all_mac.sh elif [[ "${{ runner.os }}" == "Windows" ]]; then ./build_tools/before_all_windows.sh else echo "Unrecognized OS: '${{ inputs.os }}'." exit 1 fiiqtree-piqtree-b8a3d6a/.github/actions/setup-piqtree/000077500000000000000000000000001521173175100227565ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/.github/actions/setup-piqtree/action.yml000066400000000000000000000017021521173175100247560ustar00rootroot00000000000000name: Setup piqtree description: "Setup Python and Fetch Static Library." inputs: python-version: description: "Python version." required: true cache-key: description: "Key for static library cache." required: true runs: using: composite steps: - uses: actions/setup-python@v6 with: python-version: ${{ inputs.python-version }} - name: Cache IQ-TREE (Windows) if: runner.os == 'Windows' uses: actions/cache/restore@v5 id: cache-windows with: key: ${{ inputs.cache-key }} path: | src/piqtree/_libiqtree/iqtree.lib src/piqtree/_libiqtree/iqtree.dll fail-on-cache-miss: true - name: Cache IQ-TREE (Linux/macOS) if: runner.os != 'Windows' uses: actions/cache/restore@v5 id: cache-unix with: key: ${{ inputs.cache-key }} path: | src/piqtree/_libiqtree/libiqtree.a fail-on-cache-miss: true iqtree-piqtree-b8a3d6a/.github/dependabot.yml000066400000000000000000000021331521173175100213360ustar00rootroot00000000000000# To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file version: 2 updates: - package-ecosystem: "pip" # See documentation for possible values directory: "/" # Location of package manifests schedule: interval: "weekly" open-pull-requests-limit: 10 - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" open-pull-requests-limit: 10 - package-ecosystem: "github-actions" directory: "/.github/actions/build-iqtree/" schedule: interval: "weekly" open-pull-requests-limit: 10 - package-ecosystem: "github-actions" directory: "/.github/actions/setup-piqtree/" schedule: interval: "weekly" open-pull-requests-limit: 10 - package-ecosystem: "gitsubmodule" directory: "/" schedule: interval: "daily" iqtree-piqtree-b8a3d6a/.github/workflows/000077500000000000000000000000001521173175100205445ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/.github/workflows/add_source_to_release.yml000066400000000000000000000016611521173175100256050ustar00rootroot00000000000000name: Attach Full Source to Release on: release: types: [published] permissions: contents: write jobs: upload-source: runs-on: ubuntu-latest env: VERSION: ${{ github.ref_name }} TARBALL: piqtree-${{ github.ref_name }}.tar.gz steps: - uses: actions/checkout@v6 with: fetch-depth: 0 submodules: recursive - name: Make Tarball run: | tar czf "../$TARBALL" \ --transform "s,^\.,piqtree-${VERSION}," \ --exclude-vcs . mv "../$TARBALL" "$TARBALL" - name: Compute SHA256 Checksum run: sha256sum "$TARBALL" > "$TARBALL.sha256" - name: Upload Full Source and SHA256 to GitHub Release uses: softprops/action-gh-release@v3.0.0 with: files: | ${{ env.TARBALL }} ${{ env.TARBALL }}.sha256 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}iqtree-piqtree-b8a3d6a/.github/workflows/build_container.yml000066400000000000000000000012631521173175100244320ustar00rootroot00000000000000name: Build and Push Docker Image to ghcr on: workflow_dispatch: push: branches: - main paths: - .devcontainer/DockerFile permissions: contents: read packages: write jobs: build-and-push: runs-on: ubuntu-latest steps: - name: Checkout Repository uses: actions/checkout@v6 - name: Login to GitHub Container Registry run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u iqtree --password-stdin - name: Build and Push Base Docker Image run: | docker build -f .devcontainer/DockerFile . \ -t ghcr.io/iqtree/piqtree:latest docker push ghcr.io/iqtree/piqtree:latest iqtree-piqtree-b8a3d6a/.github/workflows/build_docs.yml000066400000000000000000000026671521173175100234110ustar00rootroot00000000000000name: Build Docs concurrency: group: docs-build-${{ github.ref }} cancel-in-progress: true on: workflow_dispatch: push: branches: - main paths: - 'docs/**' - '.readthedocs.yaml' - 'mkdocs.yml' - 'rtd_get_docs.py' permissions: contents: read jobs: build-iqtree: name: Fetch or Build IQ-TREE Static Library runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: fetch-depth: 0 submodules: recursive - id: build uses: ./.github/actions/build-iqtree with: os: ubuntu-latest outputs: iqtree-sha: ${{steps.build.outputs.iqtree-sha}} build-docs: runs-on: ubuntu-latest needs: build-iqtree steps: - name: Checkout Repository uses: actions/checkout@v6 with: fetch-depth: 0 submodules: recursive - uses: ./.github/actions/setup-piqtree with: python-version: "3.14" cache-key: libiqtree-ubuntu-latest-${{ needs.build-iqtree.outputs.iqtree-sha }} - name: Install Docs Dependencies run: | pip install .[doc] - name: Build Documentation run: | mkdocs build working-directory: ${{ github.workspace }} - name: Upload Documentation Artifact uses: actions/upload-artifact@v7 with: name: piqtree-docs-html path: site iqtree-piqtree-b8a3d6a/.github/workflows/build_wheels.yml000066400000000000000000000052611521173175100237410ustar00rootroot00000000000000name: Build Wheels on: [workflow_dispatch] permissions: contents: read jobs: build: name: Build Wheels for ${{matrix.platform_id}} on ${{matrix.os}} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: # manylinux x86_64 - os: ubuntu-latest platform_id: manylinux_x86_64 # MacOS arm64 - os: macos-15 platform_id: macosx_arm64 # Windows x86_64 - os: windows-latest platform_id: win_amd64 steps: - uses: actions/checkout@v6 with: fetch-depth: 0 submodules: recursive - name: Set up QEMU for Linux ARM builds if: ${{runner.os == 'Linux' && endsWith(matrix.platform_id, '_aarch64')}} uses: docker/setup-qemu-action@v4 with: platforms: arm64 - name: Set macOS Deployment Target if: runner.os == 'macOS' run: | echo "MACOSX_DEPLOYMENT_TARGET=15.0" >> $GITHUB_ENV - name: Install Boost if: runner.os == 'Windows' uses: MarkusJx/install-boost@v2.6.0 id: install-boost with: boost_version: 1.84.0 platform_version: 2022 toolset: mingw - name: Setup MSVC Developer Command Prompt if: runner.os == 'Windows' uses: ilammy/msvc-dev-cmd@v1 - name: Build Wheels uses: pypa/cibuildwheel@v4.0.0 env: # Can specify per os - e.g. CIBW_BEFORE_ALL_LINUX, CIBW_BEFORE_ALL_MACOS, CIBW_BEFORE_ALL_WINDOWS CIBW_BEFORE_ALL_LINUX: ./build_tools/before_all_linux.sh CIBW_BEFORE_ALL_MACOS: ./build_tools/before_all_mac.sh CIBW_BEFORE_ALL_WINDOWS: bash ./build_tools/before_all_windows.sh CIBW_ENVIRONMENT_WINDOWS: Boost_INCLUDE_DIR='${{ steps.install-boost.outputs.BOOST_ROOT }}/include' Boost_LIBRARY_DIRS='${{ steps.install-boost.outputs.BOOST_ROOT }}/lib' CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: >- delvewheel repair --add-path src/piqtree/_libiqtree -w {dest_dir} {wheel} CIBW_ARCHS_LINUX: ${{endsWith(matrix.platform_id, '_x86_64') && 'x86_64' || 'aarch64'}} CIBW_ARCHS_MACOS: ${{endsWith(matrix.platform_id, 'universal2') && 'universal2' || 'auto'}} CIBW_ARCHS_WINDOWS: ${{endsWith(matrix.platform_id, '_amd64') && 'AMD64' || 'ARM64'}} CIBW_BUILD: "*${{matrix.platform_id}}" CIBW_SKIP: "cp314t-*" CIBW_TEST_REQUIRES: pytest pytest-mock CIBW_TEST_COMMAND: pytest {package}/tests - name: Upload Wheels uses: actions/upload-artifact@v7 with: name: cibw-wheels-${{ matrix.platform_id }} path: ./wheelhouse/*.whl iqtree-piqtree-b8a3d6a/.github/workflows/ci.yml000066400000000000000000000105711521173175100216660ustar00rootroot00000000000000name: CI concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true on: workflow_dispatch: schedule: - cron: "35 4 */6 * *" # Every 6 days. pull_request: push: branches-ignore: - 'dependabot/**' permissions: contents: read jobs: build-iqtree: name: Fetch or Build IQ-TREE Static Library on ${{matrix.os}} runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-15, windows-latest] # Intel linux, ARM Mac, Windows steps: - uses: actions/checkout@v6 with: fetch-depth: 0 submodules: recursive - id: build uses: ./.github/actions/build-iqtree with: os: ${{ matrix.os }} outputs: iqtree-sha: ${{steps.build.outputs.iqtree-sha}} tests: name: Run Tests with Python ${{matrix.python-version}} on ${{matrix.os}} needs: build-iqtree runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-15, windows-latest] # Intel linux, ARM Mac, Windows python-version: ["3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v6 with: fetch-depth: 0 submodules: recursive - uses: ./.github/actions/setup-piqtree with: python-version: ${{ matrix.python-version }} cache-key: libiqtree-${{ matrix.os }}-${{ needs.build-iqtree.outputs.iqtree-sha }} - name: Install llvm (macOS) if: runner.os == 'macOS' run: | brew install llvm - name: Install llvm (Windows) if: runner.os == 'Windows' run: | choco install -y llvm --version=14.0.6 --allow-downgrade - name: Run Nox Testing run: | pip install nox nox -s test-${{ matrix.python-version }} -- --cov --cov-report=lcov:${{matrix.os}}-${{matrix.python-version}}.lcov --cov-report=term --cov-append --durations=20 - name: Coveralls Parallel uses: coverallsapp/github-action@v2 with: parallel: true github-token: ${{secrets.github_token}} flag-name: run-${{matrix.python-version}}-${{matrix.os}} file: "${{matrix.os}}-${{matrix.python-version}}.lcov" upload-coverage: name: Finish Coveralls needs: tests runs-on: ubuntu-latest steps: - name: Coveralls Finished uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.github_token }} parallel-finished: true type_check: name: Type Check needs: build-iqtree runs-on: ${{ matrix.os }} strategy: matrix: python-version: ["3.14"] os: [ubuntu-latest] steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - uses: ./.github/actions/setup-piqtree with: python-version: ${{ matrix.python-version }} cache-key: libiqtree-${{ matrix.os }}-${{ needs.build-iqtree.outputs.iqtree-sha }} - name: "Run Type Checking for ${{ matrix.python-version }}" run: | pip install nox nox -s type_check-${{ matrix.python-version }} lint: name: Linting needs: build-iqtree runs-on: ${{ matrix.os }} strategy: matrix: python-version: ["3.14"] os: [ubuntu-latest] steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - uses: ./.github/actions/setup-piqtree with: python-version: ${{ matrix.python-version }} cache-key: libiqtree-${{ matrix.os }}-${{ needs.build-iqtree.outputs.iqtree-sha }} - name: "Run Linting for ${{ matrix.python-version }}" run: | pip install nox nox -s ruff-${{ matrix.python-version }} test-docs: name: Test Code Blocks in Docs needs: build-iqtree runs-on: ${{ matrix.os }} strategy: matrix: python-version: ["3.14"] os: [ubuntu-latest] steps: - uses: actions/checkout@v6 with: fetch-depth: 0 submodules: recursive - uses: ./.github/actions/setup-piqtree with: python-version: ${{ matrix.python-version }} cache-key: libiqtree-${{ matrix.os }}-${{ needs.build-iqtree.outputs.iqtree-sha }} - name: Test Code Blocks in Docs run: | pip install nox nox -s test_docs-${{ matrix.python-version }} iqtree-piqtree-b8a3d6a/.github/workflows/release.yml000066400000000000000000000114251521173175100227120ustar00rootroot00000000000000name: Release on: [workflow_dispatch] permissions: contents: read jobs: build-wheels: name: Build Wheels for ${{matrix.platform_id}} on ${{matrix.os}} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: include: # manylinux x86_64 - os: ubuntu-latest platform_id: manylinux_x86_64 # MacOS arm64 - os: macos-15 platform_id: macosx_arm64 # Windows x86_64 - os: windows-latest platform_id: win_amd64 steps: - uses: actions/checkout@v6 with: fetch-depth: 0 submodules: recursive - name: Set up QEMU for Linux ARM builds if: ${{runner.os == 'Linux' && endsWith(matrix.platform_id, '_aarch64')}} uses: docker/setup-qemu-action@v4 with: platforms: arm64 - name: Set macOS Deployment Target if: runner.os == 'macOS' run: | echo "MACOSX_DEPLOYMENT_TARGET=15.0" >> $GITHUB_ENV - name: Install Boost if: runner.os == 'Windows' uses: MarkusJx/install-boost@v2.6.0 id: install-boost with: boost_version: 1.84.0 platform_version: 2022 toolset: mingw - name: Setup MSVC Developer Command Prompt if: runner.os == 'Windows' uses: ilammy/msvc-dev-cmd@v1 - name: Build Wheels uses: pypa/cibuildwheel@v4.0.0 env: # Can specify per os - e.g. CIBW_BEFORE_ALL_LINUX, CIBW_BEFORE_ALL_MACOS, CIBW_BEFORE_ALL_WINDOWS CIBW_BEFORE_ALL_LINUX: ./build_tools/before_all_linux.sh CIBW_BEFORE_ALL_MACOS: ./build_tools/before_all_mac.sh CIBW_BEFORE_ALL_WINDOWS: bash ./build_tools/before_all_windows.sh CIBW_ENVIRONMENT_WINDOWS: Boost_INCLUDE_DIR='${{ steps.install-boost.outputs.BOOST_ROOT }}/include' Boost_LIBRARY_DIRS='${{ steps.install-boost.outputs.BOOST_ROOT }}/lib' CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: >- delvewheel repair --add-path src/piqtree/_libiqtree -w {dest_dir} {wheel} CIBW_ARCHS_LINUX: ${{endsWith(matrix.platform_id, '_x86_64') && 'x86_64' || 'aarch64'}} CIBW_ARCHS_MACOS: ${{endsWith(matrix.platform_id, 'universal2') && 'universal2' || 'auto'}} CIBW_ARCHS_WINDOWS: ${{endsWith(matrix.platform_id, '_amd64') && 'AMD64' || 'ARM64'}} CIBW_BUILD: "*${{matrix.platform_id}}" CIBW_SKIP: "cp314t-*" CIBW_TEST_REQUIRES: pytest pytest-mock CIBW_TEST_COMMAND: pytest {package}/tests - name: Upload Wheels uses: actions/upload-artifact@v7 with: name: cibw-wheels-${{ matrix.platform_id }} path: ./wheelhouse/*.whl build-iqtree: name: Fetch or Build IQ-TREE Static Library runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: fetch-depth: 0 submodules: recursive - id: build uses: ./.github/actions/build-iqtree with: os: ubuntu-latest outputs: iqtree-sha: ${{steps.build.outputs.iqtree-sha}} build-docs: runs-on: ubuntu-latest needs: build-iqtree steps: - name: Checkout Repository uses: actions/checkout@v6 with: fetch-depth: 0 submodules: recursive - uses: ./.github/actions/setup-piqtree with: python-version: "3.14" cache-key: libiqtree-ubuntu-latest-${{ needs.build-iqtree.outputs.iqtree-sha }} - name: Install Docs Dependencies run: | pip install .[doc] - name: Build Documentation run: | mkdocs build working-directory: ${{ github.workspace }} - name: Upload Documentation Artifact uses: actions/upload-artifact@v7 with: name: piqtree-docs-html path: site release-test: name: Release to Test PyPI needs: [build-wheels, build-docs] environment: release runs-on: ubuntu-latest permissions: id-token: write steps: - name: Download Artifacts uses: actions/download-artifact@v8 with: pattern: cibw-* path: dist merge-multiple: true - name: Publish Package Distributions to Test PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: repository-url: https://test.pypi.org/legacy/ release: name: Release to PyPI needs: release-test environment: release runs-on: ubuntu-latest permissions: id-token: write steps: - name: Download Artifacts uses: actions/download-artifact@v8 with: pattern: cibw-* path: dist merge-multiple: true - name: Publish Package Distributions to PyPI uses: pypa/gh-action-pypi-publish@release/v1iqtree-piqtree-b8a3d6a/.gitignore000066400000000000000000000066361521173175100171520ustar00rootroot00000000000000# vscode .vscode # iqtree *.bionj *.ckp.gz *.iqtree *.log *.mldist *.treefile # piqtree specific ignores src/piqtree/_libiqtree/**/*.a src/piqtree/_libiqtree/**/*.dll src/piqtree/_libiqtree/**/*.lib src/*.dll # docs /data/ /my_alignment.fasta /my_protein.fasta # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports lcov.info htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: # .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # poetry # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. # This is especially recommended for binary packages to ensure reproducibility, and is more # commonly ignored for libraries. # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control #poetry.lock # pdm # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. #pdm.lock # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it # in version control. # https://pdm.fming.dev/latest/usage/project/#working-with-version-control .pdm.toml .pdm-python .pdm-build/ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ # PyCharm # JetBrains specific template is maintained in a separate JetBrains.gitignore that can # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ #Ignore vscode AI rules .github/instructions/codacy.instructions.md iqtree-piqtree-b8a3d6a/.gitmodules000066400000000000000000000001441521173175100173230ustar00rootroot00000000000000[submodule "iqtree3"] path = iqtree3 url = https://github.com/iqtree/iqtree3.git branch = master iqtree-piqtree-b8a3d6a/.readthedocs.yaml000066400000000000000000000011751521173175100204020ustar00rootroot00000000000000# .readthedocs.yaml # Read the Docs configuration file for MkDocs projects # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the version of Python and other tools you might need build: os: ubuntu-22.04 tools: python: "3.14" commands: # Install the required dependencies - pip install requests # Run the script to download and extract the pre-built docs - python rtd_get_docs.py - echo "Documentation downloaded and extracted" # Disable the default build processes since we're using pre-built docs sphinx: configuration: null python: install: [] iqtree-piqtree-b8a3d6a/CODE_OF_CONDUCT.md000066400000000000000000000122261521173175100177510ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement by emailing Gavin Huttley. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. iqtree-piqtree-b8a3d6a/LICENSE000066400000000000000000000431761521173175100161670ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {description} Copyright (C) {year} {fullname} This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. {signature of Ty Coon}, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. iqtree-piqtree-b8a3d6a/README.md000066400000000000000000000066701521173175100164370ustar00rootroot00000000000000# piqtree [![PyPI Version](https://img.shields.io/pypi/v/piqtree)](https://pypi.org/project/piqtree/) [![Python Version](https://img.shields.io/pypi/pyversions/piqtree)](https://pypi.org/project/piqtree/) [![License](https://img.shields.io/github/license/iqtree/piqtree)](https://github.com/iqtree/piqtree/blob/main/LICENSE) [![CI](https://github.com/iqtree/piqtree/workflows/CI/badge.svg)](https://github.com/iqtree/piqtree/actions/workflows/ci.yml) [![Coverage Status](https://coveralls.io/repos/github/iqtree/piqtree/badge.svg?branch=main)](https://coveralls.io/github/iqtree/piqtree?branch=main) [![Documentation Status](https://readthedocs.org/projects/piqtree/badge/?version=latest)](https://piqtree.readthedocs.io/en/latest/?badge=latest) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) `piqtree` (pronounced 'pie-cue-tree') is a library which allows you to use IQ-TREE directly from Python! The interface with Python is through [cogent3](https://cogent3.org) objects. For usage, please refer to the [documentation](https://piqtree.readthedocs.io/) or the examples below. If you encounter any problems or have any feature requests feel free to raise an [issue](https://github.com/iqtree/piqtree/issues)! ## Contributing If you would like to help out by contributing to the piqtree project, please check out our [contributor guide](https://piqtree.readthedocs.io/en/latest/developers/)! ## Examples ### Phylogenetic Reconstruction ```python from piqtree import build_tree from cogent3 import load_aligned_seqs # Included with piqtree! # Load Sequences aln = load_aligned_seqs("tests/data/example.fasta", moltype="dna") aln = aln.take_seqs(["Human", "Chimpanzee", "Rhesus", "Mouse"]) # Reconstruct a phylogenetic tree with IQ-TREE! tree = build_tree(aln, "JC", rand_seed=1) # Optionally specify a random seed. print("Tree topology:", tree) # A cogent3 tree object print("Log-likelihood:", tree.params["lnL"]) # In a Jupyter notebook, try tree.get_figure() to see a dendrogram ``` > **Note** > See the [cogent3 docs](https://cogent3.org) for examples on what you can do with cogent3 trees. ### Fit Branch Lengths to Tree Topology ```python from piqtree import fit_tree from cogent3 import load_aligned_seqs, make_tree # Load Sequences aln = load_aligned_seqs("tests/data/example.fasta", moltype="dna") aln = aln.take_seqs(["Human", "Chimpanzee", "Rhesus", "Mouse"]) # Construct tree topology tree = make_tree("(Human, Chimpanzee, (Rhesus, Mouse));") # Fit branch lengths with IQ-TREE! tree = fit_tree(aln, tree, "JC") print("Tree with branch lengths:", tree) print("Log-likelihood:", tree.params["lnL"]) ``` ## More For more examples ranging from using ModelFinder and AliSim, to making rapid neighbour-joining trees, or randomly generated trees be sure to check out the [documentation](https://piqtree.readthedocs.io/)! ## Citation Please cite ```bibtex @article{10.1093/molbev/msag061, author = {McArthur, Robert Neil and Wong, Thomas King-Fung and Lang, Yapeng and Morris, Richard Andrew and Caley, Katherine and Mallawaarachchi, Vijini and Minh, Bui Quang and Huttley, Gavin}, title = {piqtree: A Python Package for Seamless Phylogenetic Inference with IQ-TREE}, journal = {Molecular Biology and Evolution}, year = {2026}, pages = {msag061}, doi = {10.1093/molbev/msag061}, url = {https://doi.org/10.1093/molbev/msag061}, } ```iqtree-piqtree-b8a3d6a/build_tools/000077500000000000000000000000001521173175100174665ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/build_tools/before_all_linux.sh000077500000000000000000000005661521173175100233450ustar00rootroot00000000000000if command -v apt-get &> /dev/null; then apt-get update -y && apt-get install -y libeigen3-dev libboost-all-dev elif command -v yum &> /dev/null; then yum update -y && yum install -y eigen3-devel boost-devel elif command -v apk &> /dev/null; then apk update && apk add eigen-dev boost-dev else echo "Unsupported package manager"; exit 1; fi bash build_tools/build_iqtree.shiqtree-piqtree-b8a3d6a/build_tools/before_all_mac.sh000077500000000000000000000010151521173175100227340ustar00rootroot00000000000000# Check if running in GitHub Actions if [ "$GITHUB_ACTIONS" = "true" ]; then brew update fi brew install llvm eigen@3 boost libomp make export LDFLAGS="-L$(brew --prefix libomp)/lib" export CPPFLAGS="-I$(brew --prefix libomp)/include -I$(brew --prefix eigen@3)/include" export CXXFLAGS="-I$(brew --prefix libomp)/include" export CMAKE_PREFIX_PATH="$(brew --prefix eigen@3):${CMAKE_PREFIX_PATH:-}" export PKG_CONFIG_PATH="$(brew --prefix eigen@3)/share/pkgconfig:${PKG_CONFIG_PATH:-}" bash build_tools/build_iqtree.sh iqtree-piqtree-b8a3d6a/build_tools/before_all_windows.sh000066400000000000000000000010201521173175100236570ustar00rootroot00000000000000# Install dependencies using choco export Boost_INCLUDE_DIR=$(echo $Boost_INCLUDE_DIR | sed 's|\\|/|g') export Boost_LIBRARY_DIRS=$(echo $Boost_LIBRARY_DIRS | sed 's|\\|/|g') echo "Boost_INCLUDE_DIR: $Boost_INCLUDE_DIR" echo "Boost_LIBRARY_DIRS: $Boost_LIBRARY_DIRS" choco install -y llvm --version=14.0.6 --allow-downgrade choco install -y eigen LLVM_BIN=$(cygpath -u "${PROGRAMFILES}\\LLVM\\bin") export PATH="$LLVM_BIN:$PATH" export CC=clang.exe export CXX=clang++.exe # Build IQ-TREE bash build_tools/build_iqtree.sh iqtree-piqtree-b8a3d6a/build_tools/build_iqtree.sh000077500000000000000000000025461521173175100225040ustar00rootroot00000000000000cd iqtree3 rm -rf build mkdir build && cd build if [[ "$OSTYPE" == "darwin"* ]]; then echo "Building for macOS." echo $LDFLAGS echo $CPPFLAGS echo $CXXFLAGS cmake -DBUILD_LIB=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ .. gmake -j elif [[ "$OSTYPE" == "msys"* || "$OSTYPE" == "cygwin"* ]]; then echo "Building for Windows." if [[ -n "$BOOST_ROOT" ]]; then export Boost_INCLUDE_DIR="${BOOST_ROOT}" export Boost_LIBRARY_DIRS="${BOOST_ROOT}" fi cmake -G "MinGW Makefiles" \ -DCMAKE_C_COMPILER=clang \ -DCMAKE_CXX_COMPILER=clang++ \ -DCMAKE_C_FLAGS=--target=x86_64-pc-windows-gnu \ -DCMAKE_CXX_FLAGS=--target=x86_64-pc-windows-gnu \ -DCMAKE_MAKE_PROGRAM=make \ -DBoost_INCLUDE_DIR=$Boost_INCLUDE_DIR \ -DBoost_LIBRARY_DIRS=$Boost_LIBRARY_DIRS \ -DIQTREE_FLAGS="cpp14" \ -DBUILD_LIB=ON \ .. make -j else echo "Building for linux." cmake -DBUILD_LIB=ON -DCMAKE_POLICY_VERSION_MINIMUM=3.5 .. make -j fi cd ../.. if [[ "$OSTYPE" == "darwin"* || "$OSTYPE" == "linux"* ]]; then mv iqtree3/build/libiqtree.a src/piqtree/_libiqtree/ elif [[ "$OSTYPE" == "msys"* || "$OSTYPE" == "cygwin"* ]]; then mv iqtree3/build/iqtree.lib src/piqtree/_libiqtree/ mv iqtree3/build/iqtree.dll src/piqtree/_libiqtree/ fi iqtree-piqtree-b8a3d6a/changelog.d/000077500000000000000000000000001521173175100173205ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/changelog.d/README.md000066400000000000000000000052141521173175100206010ustar00rootroot00000000000000# Adding changelog entries This directory is used to store changelog fragments for the next release of the project. Each file should contain a small changelog fragment that will be added to the full changelog when the release is made. The file is created using ``` scriv create --edit ``` to create a change entry This will create a file with the correct name and format and commented out sample categories, and load it into your `git` editor (the one specified by ```git config --global core.editor``` ) Uncomment the category of change you are making and add a short description of the change as a markdown bullet point. For example: Contributors * khiron ENH * Added a new feature that allows users to do Y DEP * Removed deprecated feature Z BUG * Fixed a bug that caused the project to crash when a user did X by doing Y instead DOC * Documented feature Z Check the file in with your changes. --- # Building a changelog To build the changelog for the next release, run ``` scriv collect ``` This will create a file called `CHANGELOG.md` in the root of the project. This file will contain the full changelog for the project, including all the fragments that have been added to the changelog.d directory and remove those fragments. Note this requires that the `__init__.py` file's `__version__` variable is updated from the last time you ran collect, otherwise you will get a warning ``` Entry 'Changes since release 0.0.1' already uses version '0.0.1'. ``` ... and the fragments will not be collected. When the `__version__` variable in the project is updated the next time you run collect, the fragments will be collected and the changelog will be updated. You can override this to create a new collection of all available fragments that are not aligned with a `__version__` with ``` scriv collect --version "description of a milestone not yet used" ``` --- # Releasing a new version To release a version of the project, run ``` scriv release ``` This will create a new tag in the `git` repository, and create a new release on GitHub. The release will contain the full changelog for the project, and the tag will be annotated with the full changelog as well. Note you will need to have a GitHub classic personal access token set up in your environment (GITHUB_TOKEN) for this to work. If you are using VS code and powershell you can add the following to your `settings.json` file to set the environment variable for the terminal. If you are using a different terminal you will need to set the environment variable in the appropriate way for your terminal. ```json "terminal.integrated.env.windows": { "GITHUB_TOKEN": "ghp_...", } ``` --- iqtree-piqtree-b8a3d6a/changelog.d/templates/000077500000000000000000000000001521173175100213165ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/changelog.d/templates/new.md.j2000066400000000000000000000003541521173175100227450ustar00rootroot00000000000000 {% for cat in config.categories -%} {% endfor -%} iqtree-piqtree-b8a3d6a/changelog.d/templates/new.rst.j2000066400000000000000000000005601521173175100231540ustar00rootroot00000000000000.. A new scriv changelog fragment. {% if config.categories -%} .. .. Uncomment the header that is right (remove the leading dots). .. {% for cat in config.categories -%} .. {{ cat }} .. {{ config.rst_header_chars[1] * (cat|length) }} .. .. - A bullet item for the {{ cat }} category. .. {% endfor -%} {% else %} - A bullet item for this fragment. EDIT ME! {% endif -%}iqtree-piqtree-b8a3d6a/changelog.d/templates/title.md.j2000066400000000000000000000000401521173175100232650ustar00rootroot00000000000000Changes in release "{{version}}"iqtree-piqtree-b8a3d6a/changelog.md000066400000000000000000000171131521173175100174230ustar00rootroot00000000000000 # Changes in release "0.8.0" ## Contributors - @rmcar17 - Python `simulate_alignment` implementation, documentation, project maintanence and Python processing of additional cli options. - @thomaskf - IQ-TREE library interface maintanence and enhancements (including processing additional cli options!). - @trongnhanuit & @The-CodeBreakeR - AliSim implementation. - @YapengLang - processing UNREST model parameters and storing additional values on returned tree objects. ## ENH - AliSim can now be used through `simulate_alignment`. - Additional command line options can now be sent to `build_tree`, `fit_tree` and `model_finder` with the `other_options` parameter. - UNREST model parameters are now populated on generated trees. - More specific type information is now used across a suite of functions. - The used model name is now stored on trees generated by `build_tree`. ## API - A seed of 0 is now deterministic across all IQ-TREE functions. `None` must be used (the default) for non-determinism. ## DOC - Various enhancements to grammar/spelling. - Add sections for `simulate_alignment`. # Changes in release "0.7.0" ## Contributors - @rmcar17, fixed a jupyter bug on windows and unwanted behaviour when taxon names contained underscores. - @thomaskf and @rmcar17 implemented the ability to fix certain branch lengths when using `fit_tree`. ## ENH - Add an option to fix branch lengths when using `fit_tree` called `bl_fixed`. ## BUG - `piqtree` now works in jupyter notebooks on windows platforms, like it already does for the others. - Fix unexpected behaviour when taxon names contain underscores when using `fit_tree`. # Changes in release "0.6.1" ## Contributors - @GavinHuttley docs - @rmcar17 dependencies ## BUG - Pin build dependencies for reproducible builds and use new delvewheel `get_all_needed` API. ## DOC - Update examples to the latest Cogent3 API. # Changes in release "0.6.0" ## Contributors - @rmcar17 and @thomaskf enabled windows support for piqtree! - @rmcar17 ensured `nj_tree` raises an appropriate error on NaN input. - @rmcar17 reworked `random_trees` and the related app to become `random_tree`, returning a single tree. - @rmcar17 and @thomaskf integrated IQ-TREE 3 into piqtree. - @rmcar17 added support for Lie Markov Model prefixes. - @rmcar17 added the STRSYM and UNREST models. - @rmcar17 added source tracking for the inputs of apps. - @rmcar17 and @thomaskf integrated consensus tree contruction into `piqtree`. - @rmcar17 added support for the parameterisation of currently supported models, base frequencies, and rate heterogeneity. ## ENH - Added windows support! - Add `random_tree` and `piqtree_random_tree`. The function and app have the same parameters as the `random_trees` and `piqtree_random_trees` versions, except the `num_trees` argument has been removed. - `piqtree` now uses IQ-TREE 3 for its internal library. - Add support for Lie Markov Model prefixes. - Add the STRSYM and UNREST models. - `piqtree` apps now track the sources of their inputs. - Add a method for building consensus trees with specifiable support parameters. - Add a consensus tree app. - Substitution models, base frequencies, and models for rateheterogeneity can now be parameterised. ## BUG - An error is now raised when calling `nj_tree` with NaN distances instead of failing silently. ## API - Split Lie Markov Models out of the standard dna enum. - Remove unused `rand_seed` from `fit_tree`. - All apps have been renamed to take the form `piq_`. - `random_trees` and `piqtree_random_trees` have been removed in favour of `random_tree` and `piq_random_tree`. Looping can be used if multiple trees are needed. # Changes in release "0.5.0" ## Contributors - @GavinHuttley added `nj_tree` as a hook for `cogent3.Alignment.quick_tree`. - @YapengLang handled negative branch lengths from the rapidNJ tree. - @rmcar17, @thomaskf general maintanence on the piqtree/IQ-TREE sides including work on windows behind the scenes. ## ENH - Add support for Python 3.13, remove support for 3.10 - IQ-TREE's rapidNJ implementation can be used as a hook for `quick_tree` on `cogent3` alignment objects. Try `Alignment.quick_tree(use_hook="piqtree")`. - `nj_tree` now by default does not allow negative branch lengths. Set `allow_negative=True` if this behaviour is desired. - Allow `str` to be used for `model` in `build_tree` and `fit_tree`. The value is automatically coerced into the `Model` class. ## API - Simplify API for `piqtree_phylo` and `piqtree_fit` apps. Both now take a single parameter for the model, matching the parameter for `model` in `build_tree` and `fit_tree`. # Changes in release "0.4.0" ## Contributors - @rmcar17 integrated new functions from IQ-TREE in Python, added multithreading support, and wrote the API refererence and quickstart. - @thomaskf exposed all new functions from IQ-TREE to be available from Python, and worked on multithreading support. - @GavinHuttley worked on setting up and writing the documentation and associated devtools, ModelFinder, and integration with `cogent3` apps. - @YapengLang worked on bootstrapping support and extracting model parameters - @KatherineCaley worked on processing the ModelFinder results. ## ENH - piqtree2 renamed piqtree to support future major releases of IQ-TREE. - piqtree now supports multithreading! - New function `nj_tree` constructs a rapid neighbour-joining tree from a pairwise distance matrix. - New function `model_finder` finds the best model for a given alignment. - New function `jc_distances` constructs a pairwise JC distance matrix from an alignment. - New function `make_model` allows converting an IQ-TREE string representation of a model to a `Model` class. - API for `random_trees` has changed - new order (`num_trees`, `num_taxa`, `tree_mode`, then `rand_seed`). - API for `robinson_foulds` has changed - now accepts a Sequence of trees. - Model parameters are now extracted from IQ-TREE where for now possible. - `build_tree` now supports ultrafast bootstrapping. - `Model` creation is now more robust. - Use `piqtree.__iqtree_version__` to see what version of piqtree is being used. - See what can now be done in our [new documentation](https://piqtree.readthedocs.io)! ## DOC - [Documentation](https://piqtree.readthedocs.io) is now on readthedocs! # Changes in release "0.3.1" ## ENH - Add support for Lie Markov Models. - Base frequencies default to None (specified by model). ## BUG - `piqtree2` apps are now pickleable (they can now be run with `parallel=True` in the cogent3 app infrastructure) # Changes in release "0.3.0" ## Contributors - @rmcar17 Added new classes to enhance model specification when calling `build_tree` and `fit_tree`. - @thomaskf fixed a bug in IQ-TREE resulting in segmentation faults on some invalid arguments. ## ENH - `build_tree` and `fit_tree` now allow specifying base frequencies, invariable sites and rate heterogeneity options. ## BUG - Fixed a segmentation fault on repetitive calls to IQ-TREE with particular arguments. # Changes in release "0.2.0" ## Contributors - Richard Morris - Robert McArthur ## ENH - `build_tree` and `fit_tree` now use enums for the substitution model. ## BUG - Fixed an issue where calling `build_tree` or `fit_tree` twice, then another function with invalid input resulted in a segmentation fault. ## DOC - Implement scriv as a tool to manage collection of changes, and automated collation into the changelog iqtree-piqtree-b8a3d6a/docs/000077500000000000000000000000001521173175100160775ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/docs/api/000077500000000000000000000000001521173175100166505ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/docs/api/alignment/000077500000000000000000000000001521173175100206265ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/docs/api/alignment/simulate_alignment.md000066400000000000000000000002341521173175100250300ustar00rootroot00000000000000# simulate_alignment ::: piqtree.simulate_alignment ## Usage For usage, see ["Simulate alignments with AliSim"](../../quickstart/simulate_alignment.md). iqtree-piqtree-b8a3d6a/docs/api/genetic_distance/000077500000000000000000000000001521173175100221405ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/docs/api/genetic_distance/jc_distances.md000066400000000000000000000002361521173175100251140ustar00rootroot00000000000000# jc_distances ::: piqtree.jc_distances ## Usage For usage, see ["Calculate pairwise Jukes-Cantor distances"](../../quickstart/calculate_jc_distances.md). iqtree-piqtree-b8a3d6a/docs/api/index.md000066400000000000000000000032061521173175100203020ustar00rootroot00000000000000# API Reference Index ## Trees | Name | Summary | |------|---------| | [build_tree](tree/build_tree.md) | Construct a maximum-likelihood phylogenetic tree. | | [fit_tree](tree/fit_tree.md) | Fit branch lengths to a phylogenetic tree. | | [nj_tree](tree/nj_tree.md) | Construct rapid neighbour-joining tree from pairwise distance matrix. | | [consensus_tree](tree/consensus_tree.md) | Construct a consensus tree from a collection of trees. | | [random_tree](tree/random_tree.md) | Create a randomly generated phylogenetic tree. | ## Alignments | Name | Summary | |------|---------| | [simulate_alignment](alignment/simulate_alignment.md) | Simulate an alignment with AliSim. | ## Substitution Models | Name | Summary | |------|---------| | [model_finder](model/model_finder.md) | Determine the best-fit model for your data. | | [ModelFinderResult](model/ModelFinderResult.md) | Collection of data returned by IQ-TREE's ModelFinder. | | [Model](model/Model.md) | Class for substitution models. | | [make_model](model/make_model.md) | Function to construct Model classes from IQ-TREE strings. | | [SubstitutionModel](model/SubstitutionModel.md) | Enums for substitution models. | | [FreqType](model/FreqType.md) | Enum for base frequencies and class for custom base frequencies. | | [RateModel](model/RateModel.md) | Classes for rate heterogeneity. | ## Genetic Distances | Name | Summary | |------|---------| | [jc_distances](genetic_distance/jc_distances.md) | Pairwise Jukes-Cantor genetic distances. | ## Tree Distances | Name | Summary | |------|---------| | [robinson_foulds](tree_distance/robinson_foulds.md) | Pairwise Robinson-Foulds distances. | iqtree-piqtree-b8a3d6a/docs/api/model/000077500000000000000000000000001521173175100177505ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/docs/api/model/FreqType.md000066400000000000000000000004031521173175100220260ustar00rootroot00000000000000# FreqType ::: piqtree.model.FreqType options: show_if_no_docstring: true ::: piqtree.model.CustomBaseFreq ## Usage For usage, see ["Use different kinds of substitution models"](../../quickstart/using_substitution_models.md#base-frequencies). iqtree-piqtree-b8a3d6a/docs/api/model/Model.md000066400000000000000000000002241521173175100213300ustar00rootroot00000000000000# Model ::: piqtree.Model ## Usage For usage, see ["Use different kinds of substitution models"](../../quickstart/using_substitution_models.md). iqtree-piqtree-b8a3d6a/docs/api/model/ModelFinderResult.md000066400000000000000000000002461521173175100236630ustar00rootroot00000000000000# ModelFinderResult ::: piqtree.ModelFinderResult ## Usage For usage, see ["Find the model of best fit with ModelFinder"](../../quickstart/using_model_finder.md). iqtree-piqtree-b8a3d6a/docs/api/model/RateModel.md000066400000000000000000000003371521173175100221510ustar00rootroot00000000000000# RateModel ::: piqtree.model.DiscreteGammaModel ::: piqtree.model.FreeRateModel ## Usage For usage, see ["Use different kinds of substitution models"](../../quickstart/using_substitution_models.md#rate-heterogeneity). iqtree-piqtree-b8a3d6a/docs/api/model/SubstitutionModel.md000066400000000000000000000012461521173175100237720ustar00rootroot00000000000000# SubstitutionModel Enums for available DNA (including Lie Markov Models) and amino acid models. Strings may be used instead of the enums. ::: piqtree.model.StandardDnaModel options: show_if_no_docstring: true ::: piqtree.model.StandardDnaModelInstance options: show_if_no_docstring: true ::: piqtree.model.LieModel options: show_if_no_docstring: true ::: piqtree.model.LieModelInstance options: show_if_no_docstring: true ::: piqtree.model.AaModel options: show_if_no_docstring: true ## Usage For usage, see ["Use different kinds of substitution models"](../../quickstart/using_substitution_models.md#usage). iqtree-piqtree-b8a3d6a/docs/api/model/make_model.md000066400000000000000000000002361521173175100223700ustar00rootroot00000000000000# make_model ::: piqtree.make_model ## Usage For usage, see ["Use different kinds of substitution models"](../../quickstart/using_substitution_models.md). iqtree-piqtree-b8a3d6a/docs/api/model/model_finder.md000066400000000000000000000002341521173175100227200ustar00rootroot00000000000000# model_finder ::: piqtree.model_finder ## Usage For usage, see ["Find the model of best fit with ModelFinder"](../../quickstart/using_model_finder.md). iqtree-piqtree-b8a3d6a/docs/api/tree/000077500000000000000000000000001521173175100176075ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/docs/api/tree/build_tree.md000066400000000000000000000002341521173175100222460ustar00rootroot00000000000000# build_tree ::: piqtree.build_tree ## Usage For usage, see ["Construct a maximum likelihood phylogenetic tree"](../../quickstart/construct_ml_tree.md). iqtree-piqtree-b8a3d6a/docs/api/tree/consensus_tree.md000066400000000000000000000002601521173175100231660ustar00rootroot00000000000000# consensus_tree ::: piqtree.consensus_tree ## Usage For usage, see ["Construct a consensus tree from a collection of trees"](../../quickstart/construct_consensus_tree.md). iqtree-piqtree-b8a3d6a/docs/api/tree/fit_tree.md000066400000000000000000000002371521173175100217340ustar00rootroot00000000000000# fit_tree ::: piqtree.fit_tree ## Usage For usage, see ["Fit branch lengths to a tree topology from an alignment"](../../quickstart/fit_tree_topology.md). iqtree-piqtree-b8a3d6a/docs/api/tree/nj_tree.md000066400000000000000000000002451521173175100215600ustar00rootroot00000000000000# nj_tree ::: piqtree.nj_tree ## Usage For usage, see ["Construct a rapid neighbour-joining tree from a distance matrix"](../../quickstart/construct_nj_tree.md). iqtree-piqtree-b8a3d6a/docs/api/tree/random_tree.md000066400000000000000000000003411521173175100224260ustar00rootroot00000000000000# random_tree ::: piqtree.random_tree ::: piqtree.TreeGenMode options: show_if_no_docstring: true ## Usage For usage, see ["Make a randomly generated phylogenetic tree"](../../quickstart/make_random_tree.md). iqtree-piqtree-b8a3d6a/docs/api/tree_distance/000077500000000000000000000000001521173175100214615ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/docs/api/tree_distance/robinson_foulds.md000066400000000000000000000002651521173175100252130ustar00rootroot00000000000000# robinson_foulds ::: piqtree.robinson_foulds ## Usage For usage, see ["Calculate pairwise Robinson-Foulds distances between trees"](../../quickstart/calculate_rf_distances.md). iqtree-piqtree-b8a3d6a/docs/apps/000077500000000000000000000000001521173175100170425ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/docs/apps/app_pipeline.py000066400000000000000000000040671521173175100220700ustar00rootroot00000000000000# %% [markdown] # ## Building workflows using `piqtree` apps # > **WARNING** # > This page is under construction! # # We can combine `piqtree` apps with other cogent3 apps to develop a pipeline. There are multiple concepts involved here, particularly data stores, composed apps, parallel execution, log files etc... See the `cogent3` [app documentation](https://cogent3.org/doc/app/index.html) for more details. # # To develop a pipeline efficiently we only need a subset of the sequences in an alignment. We will use the [diverse-seq](https://pypi.org/project/diverse-seq/) plugin for that purpose. This allows selecting a specified subset of sequences that capture the diversity in an alignment. # # But first, we need the data. # %% from piqtree import download_dataset alns_path = download_dataset("mammal-orths.zip", dest_dir="data", inflate_zip=False) # %% [markdown] # We open this directory as a `cogent3` data store. # %% from cogent3 import open_data_store dstore = open_data_store(alns_path, suffix="fa") dstore.describe # %% [markdown] # We need to create some apps to: load data, a divergent sequence selector app, drop alignment columns containing non-canonical nucleotides (so gaps and N's), select alignments with a minimym number of aligned columns, a "data store" to write results to and a writer. These will then be combined into a single composed app which will be applied to all the alignments in the data store. # %% import pathlib from collections import Counter from cogent3 import get_app outpath = pathlib.Path("data/delme.sqlitedb") outpath.unlink(missing_ok=True) loader = get_app("load_aligned", format_name="fasta", moltype="dna") divergent = get_app("dvs_nmost", n=10, k=6) just_nucs = get_app("omit_degenerates") # has to go after the divergent selector min_length = get_app("min_length", length=600) best_model = get_app("piq_model_finder") app = loader + divergent + just_nucs + min_length + best_model model_counts = Counter( str(result.best_aic) for result in app.as_completed(dstore, show_progress=True, parallel=True) if result ) model_counts iqtree-piqtree-b8a3d6a/docs/apps/available_help.py000066400000000000000000000006571521173175100223540ustar00rootroot00000000000000# %% [markdown] # To see the apps that `piqtree` makes available, use the `cogent3` function `available_apps()` as follows. # %% from cogent3 import available_apps available_apps("piqtree") # %% [markdown] # For a particular app, use the `cogent3` function `app_help()` to find out what the options are. # %% from cogent3 import app_help app_help("piq_build_tree") # %% from cogent3 import app_help app_help("piq_fit_tree") iqtree-piqtree-b8a3d6a/docs/apps/fit_tree.py000066400000000000000000000025741521173175100212250ustar00rootroot00000000000000# %% [markdown] # We evaluate a support for a specific phylogeny using `piq_fit_tree`. # For this simple case, we will assess the support for a specific phylogeny using the GTR model on one alignment. # %% import cogent3 from piqtree import download_dataset aln_path = download_dataset("example.phy.gz", dest_dir="data") aln = cogent3.load_aligned_seqs(aln_path, moltype="dna", format_name="phylip") aln # %% [markdown] # We use a tree corresponding to the data in the `example.phy` file. # %% tree_path = download_dataset("example.tree.gz", dest_dir="data") tree = cogent3.load_tree(tree_path) tree.get_figure().show() # %% [markdown] # We now take a look at the help for the `piq_fit_tree` app. # %% from cogent3 import app_help app_help("piq_fit_tree") # %% [markdown] # We fit a GTR model and estimate the nucleotide frequencies by maximum likelihood. # %% from cogent3 import get_app fit_gtr = get_app("piq_fit_tree", tree, model="GTR+FO") fit_gtr # %% [markdown] # ## Fit the model # %% fit = fit_gtr(aln) # %% [markdown] # The `fit` object is a `cogent3` tree (`PhyloNode`) and the maximum likelihood estimated parameters are stored in the `params` attribute. # # > **Note** # > "lnL" is short for log likelihood and is the log likelihood of the model. # > "mprobs" is short for motif probabilities and are the estimated equilibrium frequencies of the nucleotides. # %% fit.params iqtree-piqtree-b8a3d6a/docs/apps/index.md000066400000000000000000000005201521173175100204700ustar00rootroot00000000000000# Using the `piqtree` apps - [Available apps](available_help.py) - [Selecting models for phylogenetic analysis](model_finder.py) - [Estimate a phylogenetic tree](phylo.py) - [Fit a model to one tree](fit_tree.py) - [Pairwise JC distances](pairwise_dist.py) - [NJ tree](nj.py) - [Parallel processing across alignments](app_pipeline.py) iqtree-piqtree-b8a3d6a/docs/apps/model_finder.py000066400000000000000000000023041521173175100220420ustar00rootroot00000000000000# %% [markdown] # We use the `piq_model_finder` app to rank models. This is the python binding to the IQ-TREE ModelFinder tool. # %% from cogent3 import app_help, get_app, load_aligned_seqs from piqtree import download_dataset aln_path = download_dataset("example.phy.gz", dest_dir="data") aln = load_aligned_seqs(aln_path, moltype="dna", format_name="phylip") # %% [markdown] # Get help and then apply `piq_model_finder`. # %% app_help("piq_model_finder") # %% mfinder = get_app("piq_model_finder") ranked = mfinder(aln) ranked # %% [markdown] # ## Accessing the best model # The different measures used to select the best model, AIC, AICc, and BIC, are available as attributes of the result object. We'll select AICc as the measure for choosing the best model. # %% selected = ranked.best_aicc # %% [markdown] # You can inspect the statistics for one of these using the `model_stats` attribute. # %% ranked.model_stats[selected] # %% [markdown] # ## Using the best model # You can apply the selected model to a phylogenetic analysis. # > **Note** # > The process is the same for both the `piq_build_tree` and the `piq_fit_tree` apps. # %% fit = get_app("piq_build_tree", selected) fitted = fit(aln) fitted iqtree-piqtree-b8a3d6a/docs/apps/nj.py000066400000000000000000000027661521173175100200360ustar00rootroot00000000000000# %% [markdown] # The Neighbour-Joining method uses genetic distances to build a phylogenetic tree. `piqtree` provides only `piq_jc_distances` for this. `cogent3` includes many more methods. The results of either can be used to build a tree. For divergent sequences we will use Lake's paralinear measure as it accomodates divergent sequence compositions. # %% import cogent3 from piqtree import download_dataset aln_path = download_dataset("example.phy.gz", dest_dir="data") aln = cogent3.load_aligned_seqs(aln_path, moltype="dna", format_name="phylip") # %% [markdown] # ## Getting a paralinear distance matrix # This can be obtained directly from the alignment object itself. # %% dists = aln.distance_matrix(calc="paralinear") dists # %% [markdown] # Get help on the `piq_nj_tree` app. # %% cogent3.app_help("piq_nj_tree") # %% [markdown] # Make an app and apply it to the distance matrix. # %% nj = cogent3.get_app("piq_nj_tree") tree = nj(dists) # %% [markdown] # > **Warning** # > Branch lengths can be negative in the piqtree NJ tree. This manifests as branches going backwards! # %% tree.get_figure().show() # %% [markdown] # > **Note** # > To write the tree to a file, use the `write()` method. # %% [markdown] # ## Combining the piqtree dist and nj apps # We can combine the `piq_jc_distances` and `piq_nj_tree` apps to build a tree from an alignment in one step. # %% jc = cogent3.get_app("piq_jc_distances") nj = cogent3.get_app("piq_nj_tree") app = jc + nj tree = app(aln) tree.get_figure().show() iqtree-piqtree-b8a3d6a/docs/apps/pairwise_dist.py000066400000000000000000000010561521173175100222640ustar00rootroot00000000000000# %% [markdown] # We estimate pairwise distances via the Jukes-Cantor model with the `piq_jc_distances` app. # %% import cogent3 from piqtree import download_dataset aln_path = download_dataset("example.phy.gz", dest_dir="data") aln = cogent3.load_aligned_seqs(aln_path, moltype="dna", format_name="phylip") # %% [markdown] # We get help on the `piqtree_jc_dist` app. # %% cogent3.app_help("piq_jc_distances") # %% [markdown] # Make an app and apply it to the alignment. # %% jc_dists = cogent3.get_app("piq_jc_distances") dists = jc_dists(aln) dists iqtree-piqtree-b8a3d6a/docs/apps/phylo.py000066400000000000000000000022141521173175100205460ustar00rootroot00000000000000# %% [markdown] # We use the `piq_build_tree` app to build phylogenies. # For this simple case, we will build a single phylogeny using the GTR model on one alignment. # We have a utility script for this documentation that provides the local path to that data. We will then load that data and, as it contains quite a few sequences, we will use a subset of it. We use methods on the `cogent3` object to do that. # %% import cogent3 from piqtree import download_dataset aln_path = download_dataset("example.phy.gz", dest_dir="data") aln = cogent3.load_aligned_seqs(aln_path, moltype="dna", format_name="phylip") aln # %% [markdown] # We now take a look at the help for the `piq_build_tree` app. # %% from cogent3 import app_help app_help("piq_build_tree") # %% [markdown] # We build an app for estimating phylogenies with a GTR model # %% from cogent3 import get_app phylo_gtr = get_app("piq_build_tree", model="GTR", bootstrap_reps=1000) phylo_gtr # %% [markdown] # ## Run the phylogeny estimation and display branches with support < 90%. # %% tree = phylo_gtr(aln) dnd = tree.get_figure(show_support=True, threshold=90) dnd.show(width=600, height=600) iqtree-piqtree-b8a3d6a/docs/citation.md000066400000000000000000000023001521173175100202260ustar00rootroot00000000000000# Citation Please cite piqtree as follows: McArthur RN, Wong TK-F, Lang Y, Morris RA, Caley K, Mallawaarachchi V, Minh BQ, Huttley G, 2026. "piqtree: A Python Package for Seamless Phylogenetic Inference with IQ-TREE", Molecular Biology and Evolution, msag061, [10.1093/molbev/msag061](https://doi.org/10.1093/molbev/msag061). ```bibtex @article{piqtree, author = {McArthur, Robert Neil and Wong, Thomas King-Fung and Lang, Yapeng and Morris, Richard Andrew and Caley, Katherine and Mallawaarachchi, Vijini and Minh, Bui Quang and Huttley, Gavin}, title = {piqtree: A Python Package for Seamless Phylogenetic Inference with IQ-TREE}, journal = {Molecular Biology and Evolution}, year = {2026}, pages = {msag061}, doi = {10.1093/molbev/msag061}, url = {https://doi.org/10.1093/molbev/msag061}, } ``` Please cite cogent3 as follows: Huttley, G. (2021). cogent3: comparative genomics toolkit (2020.12.21). [10.5281/zenodo.4542532](https://doi.org/10.5281/zenodo.4542532) ```bibtex @misc{cogent3, title = {cogent3: comparative genomics toolkit (2020.12.21)}, author = {Huttley, Gavin A}, year = {2021}, doi = {10.5281/zenodo.4542532}, } ``` iqtree-piqtree-b8a3d6a/docs/developers/000077500000000000000000000000001521173175100202475ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/docs/developers/contributing.md000066400000000000000000000017111521173175100233000ustar00rootroot00000000000000# Contributing to `piqtree` We welcome all contributors who would like to work on the `piqtree` project. ## Overview Contributions can be made through a GitHub pull request to the main repository. We recommend working off a new branch when contributing new features. After submitting a pull request, it will be reviewed by a member of the core dev team. It's rare for a contribution to be accepted without some edits. This is a constructive process and we hope you will find our remarks useful. Thanks for participating! ## Code formatting We use `ruff` to format the project's code. The formatter can be run in the terminal in the project's base directory: ```bash ruff format ``` ## Docstrings All public-facing functions must be documented and we strongly encourage docstrings for internal functions, particularly those with wide usage. We follow the [NumPy docstring style guide](https://numpydoc.readthedocs.io/en/latest/format.html) for all docstrings. iqtree-piqtree-b8a3d6a/docs/developers/environment_setup.md000066400000000000000000000037511521173175100243630ustar00rootroot00000000000000# Setting up your environment for development ## Initial setup Fork and clone the [`piqtree` repository](https://github.com/iqtree/piqtree). ## Working with the `iqtree3` submodule We use a git submodule to keep track of the version of IQ-TREE that is being used. To initialise the submodule, or to get the latest version after an update, the following can be run: ```bash git submodule update --init --recursive ``` ## Building the IQ-TREE library There are several build scripts used by the CI to install dependencies and build the IQ-TREE library. If you are working through the dev container, all dependencies should already be installed. The IQ-TREE library can be built with `./build_tools/build_iqtree.sh`. If you are working on a Mac, running `./build_tools/before_all_mac.sh` will install the required dependencies through homebrew, then build the IQ-TREE library. If you need to build the library again, running `./build_tools/build_iqtree.sh` will skip the dependency installation step. If you are working on linux, check the top of the `.devcontainer/DockerFile` for the list of dependencies. Once installed, the IQ-TREE library can be built with `./build_tools/build_iqtree.sh`. ## Installing `piqtree` for standard development After completing the above steps, in your preferred Python virtual environment run the following in the repository's directory: ```bash pip install -e ".[dev]" ``` This will install `piqtree` in editable mode, alongside testing, linting and other dependencies. ## Installing `piqtree` for documentation development To contribute to the documentation, we recommend running the following after the above steps in a separate virtual environment: ```bash pip install -e ".[doc]" ``` This will install `piqtree` in editable mode, along with dependencies for building the documentation. ## Running the tests To verify that installation has worked, run the following in the base directory of this repository using your chosen development environment. ```bash pytest ``` iqtree-piqtree-b8a3d6a/docs/developers/index.md000066400000000000000000000011731521173175100217020ustar00rootroot00000000000000# Contributor Guide This guide is intended for those who wish to contribute to the `piqtree` project. - See ["Setting up your environment for development"](./environment_setup.md) for setting up `piqtree`. - See ["Working with the IQ-TREE submodule"](./iqtree_submodule.md) for keeping the IQ-TREE library up to date. - See ["Contributing"](./contributing.md) for how to contribute to `piqtree`. - See ["Testing, linting, and type checking"](./testing.md) for checking your code. - See ["Troubleshooting"](./troubleshooting.md) for common problems. - See ["Release checklist"](./release.md) for releasing a new version of `piqtree`. iqtree-piqtree-b8a3d6a/docs/developers/iqtree_submodule.md000066400000000000000000000011421521173175100241370ustar00rootroot00000000000000# Working with the IQ-TREE submodule We use a submodule to keep track of the version of IQ-TREE being used. Every so often, there is an update to the submodule. This most frequently happens when new features are being added from IQ-TREE, or upon a new release. When the submodule updates, to ensure the latest version of the IQ-TREE library is being used the submodule must be updated locally and the library rebuilt. This can be done by running the following two commands in the base directory of the `piqtree` repository: ```bash git submodule update --init --recursive ./build_tools/build_iqtree.sh ``` iqtree-piqtree-b8a3d6a/docs/developers/release.md000066400000000000000000000014751521173175100222200ustar00rootroot00000000000000# Release checklist These instructions are for `piqtree` release managers. The release is largely automated by the CI, but there are several things to confirm and do in this process. The release process is automated through the "Release" GitHub Action. The documentation is fetched by readthedocs from the "Build Docs" GitHub Action. - The `piqtree` version has been correctly bumped. - The testing, linting and type checking all pass on all supported platforms. - The code has been thoroughly tested (check what's been missed in the coverage report). - The documentation builds and appears correct. - The latest version of the documentation has been updated on readthedocs (and appears correct). - The "Release" GitHub Action has correctly uploaded to Test PyPI. - The "Release" GitHub action has correctly uploaded to PyPI. iqtree-piqtree-b8a3d6a/docs/developers/testing.md000066400000000000000000000010561521173175100222500ustar00rootroot00000000000000# Testing, linting, and type checking We use `pytest` for testing, `ruff` for linting and `mypy` for type checking. Pull requests require all three of these things to pass. ## Testing To run the tests, run the following in the base directory of the `piqtree` repository: ```bash pytest ``` ## Linting To run the linting, run the following in the base directory of the `piqtree` repository: ```bash ruff check ``` ## Type checking To run type checking, run the following in the base directory of the `piqtree` repository: ```bash mypy src tests ``` iqtree-piqtree-b8a3d6a/docs/developers/troubleshooting.md000066400000000000000000000025501521173175100240220ustar00rootroot00000000000000# Troubleshooting This is a guide for common problems that may occur when working on `piqtree` development. If you have an issue that isn't listed here, please feel more than welcome to [raise an issue](https://github.com/iqtree/piqtree/issues) and we'll look into it. ## `piqtree` doesn't install There could be several reasons `piqtree` doesn't install correctly. ### Check your operating system is supported At this stage, we currently only support x86-64 linux, x86-64 Windows, and ARM macOS. ### Check the IQ-TREE library is up-to-date Try running the following to build the latest version of the IQ-TREE library. ```bash git submodule update --init --recursive ./build_tools/build_iqtree.sh ``` If the above doesn't work, please retry the guide on ["Setting up your environment for development"](./environment_setup.md). ## The IQ-TREE library doesn't build There could be several reasons `piqtree` doesn't build. ### Check your operating system is supported At this stage, we currently only support x86-64 linux, x86-64 Windows, and ARM macOS. ### Check dependencies have been installed - If on Windows, try running `./before_all_windows.sh` which will also install dependencies. - If on macOS, try running `./before_all_mac.sh` which will also install dependencies. - If on linux, try installing the dependencies listed at the top of `.devcontainer/DockerFile` iqtree-piqtree-b8a3d6a/docs/index.md000066400000000000000000000047151521173175100175370ustar00rootroot00000000000000## Overview `piqtree` (pronounced 'pie-cue-tree') is a Python package that exposes selected [IQ-TREE](http://www.iqtree.org) capabilities within Python, using the [cogent3](https://cogent3.org) library as the interface. `piqtree` is implemented with the goals of: - making the individual high-performance components of IQ-TREE available within Python, enabling the community to take advantage of these routines. - facilitating exploratory analyses by leveraging cogent3's capabilities to provide a rich user experience in interactive Jupyter notebooks, e.g. trivial parallelisation across collections of alignments. - code using piqtree apps should be easy to understand. In addition to the functions provided, `piqtree` provides mini-applications in the form of [cogent3 apps](https://cogent3.org/doc/app/index.html). These can interplay with other such apps, e.g. the [cogent3-ete3](https://pypi.org/project/cogent3-ete3/) tree conversion plugin, the [diverse-seqs](https://pypi.org/project/diverse-seq/) sequence subsampling plugin. > **Note** > `piqtree` does not implement all of the capabilities of IQ-TREE! ## Installation You get the vanilla version of `piqtree` by running the following command. ```bash pip install piqtree ``` To get Jupyter and visualisation support (with plotly) use the `[extra]` option. ```bash pip install "piqtree[extra]" ``` ## Sharing your cool solutions 😎 If you've done something you would like to share which either used `piqtree` or helped you to it (e.g. some data sampling steps with `cogent3`), please share your code on [our community contribution site](https://github.com/cogent3/c3codeshare). Contributing is as easy as clicking a button and pasting your code! Who knows, it may lead to collaborations 🙂. If you want to see how others are using `piqtree`, take a look at the site. (At the time of writing, this is very new, so there's not many contributions.) ## Getting help If you have a question about using `piqtree`, you can post a question [in the piqtree forums](https://github.com/iqtree/piqtree/discussions). Likewise, if you have any questions about using `cogent3`, post a question [in the cogent3 forums](https://github.com/cogent3/cogent3/discussions). ## Reporting problems To report problems or potential bugs 🐛, please raise an issue on the [piqtree GitHub issues page](https://github.com/iqtree/piqtree/issues). ## Citing piqtree Please cite our [preprint](https://www.biorxiv.org/content/10.1101/2025.07.13.664626v3). iqtree-piqtree-b8a3d6a/docs/llms.txt000066400000000000000000000053011521173175100176060ustar00rootroot00000000000000# piqtree > piqtree (pronounced 'pie-cue-tree') is a Python library that exposes IQ-TREE phylogenetic inference capabilities within Python, using cogent3 as the interface. ## Overview piqtree makes individual high-performance components of IQ-TREE available within Python, enabling phylogenetic analyses directly from Python code. It integrates with cogent3 for rich interactive experiences in Jupyter notebooks. ## Installation ```bash pip install piqtree pip install "piqtree[extra]" # With Jupyter and plotly support ``` ## Documentation - Main docs: https://piqtree.readthedocs.io/ - GitHub: https://github.com/iqtree/piqtree - cogent3 docs: https://cogent3.org ## Core Functions ### Tree Construction - `build_tree(alignment, model)` - Construct maximum-likelihood phylogenetic tree - `fit_tree(alignment, tree, model)` - Fit branch lengths to existing tree topology - `nj_tree(distances)` - Construct rapid neighbour-joining tree from distance matrix - `consensus_tree(trees)` - Construct consensus tree from collection of trees - `random_tree(names)` - Create randomly generated phylogenetic tree ### Alignment Simulation - `simulate_alignment(tree, model, length)` - Simulate alignment with AliSim ### Model Selection - `model_finder(alignment)` - Determine best-fit substitution model - `make_model(model_string)` - Construct Model from IQ-TREE model string - `Model` - Class for substitution models - `SubstitutionModel` - Enum for available substitution models (JC, K2P, HKY, GTR, etc.) - `FreqType` - Enum for base frequency options - `RateModel` - Classes for rate heterogeneity (+G, +I, +R) ### Distance Calculations - `jc_distances(alignment)` - Pairwise Jukes-Cantor genetic distances - `robinson_foulds(tree1, tree2)` - Pairwise Robinson-Foulds tree distances ## Quick Example ```python from piqtree import build_tree from cogent3 import load_aligned_seqs aln = load_aligned_seqs("seqs.fasta", moltype="dna") tree = build_tree(aln, "JC", rand_seed=1) print(tree) # cogent3 tree object print(tree.params["lnL"]) # log-likelihood ``` ## cogent3 Apps piqtree provides cogent3-compatible apps for use in pipelines: - `piqtree_phylo` - ML tree reconstruction - `piqtree_fit` - Fit branch lengths - `piqtree_nj` - Neighbour-joining trees - `piqtree_model_finder` - Model selection - `piqtree_pairwise_dist` - Pairwise distances ## Key Concepts - All sequence data uses cogent3 `Alignment` objects - All trees are cogent3 `PhyloNode` objects with branch lengths and likelihood info - Substitution models follow IQ-TREE naming conventions - Results include log-likelihood in `tree.params["lnL"]` ## Support - Issues: https://github.com/iqtree/piqtree/issues - Discussions: https://github.com/iqtree/piqtree/discussions iqtree-piqtree-b8a3d6a/docs/quickstart/000077500000000000000000000000001521173175100202715ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/docs/quickstart/available_frequency_options.py000066400000000000000000000003021521173175100264120ustar00rootroot00000000000000# %% [markdown] # ## State frequency types # These specify how the frequencies of nucleotides or amino acids are obtained. # %% from piqtree import available_freq_type available_freq_type() iqtree-piqtree-b8a3d6a/docs/quickstart/available_rate_heterogeneity_options.py000066400000000000000000000001721521173175100303040ustar00rootroot00000000000000# %% [markdown] # ## Site-heterogeneity model types # %% from piqtree import available_rate_type available_rate_type() iqtree-piqtree-b8a3d6a/docs/quickstart/available_submodels.py000066400000000000000000000003641521173175100246430ustar00rootroot00000000000000# %% [markdown] # ## Substitution model types # Assign the value in the "Abbreviation" column as a string to the `submod_type` parameter, e.g. # ```python # submod_type="GTR" # ``` # %% from piqtree import available_models available_models() iqtree-piqtree-b8a3d6a/docs/quickstart/calculate_jc_distances.md000066400000000000000000000022761521173175100252700ustar00rootroot00000000000000# Calculate pairwise Jukes-Cantor distances A pairwise Jukes-Cantor distance matrix can be constructed from a cogent3 alignment object using [`jc_distances`](../api/genetic_distance/jc_distances.md). The resulting distance matrix can be indexed by integer index, or by name. ## Usage ### Basic Usage Construct a `cogent3` alignment object, then calculate the pairwise JC distance matrix. ```python from cogent3 import load_aligned_seqs from piqtree import jc_distances aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") distance_matrix = jc_distances(aln) distance_1 = distance_matrix[0, 1] distance_2 = distance_matrix["Human", "Chimpanzee"] ``` ### Multithreading The number of threads to be used may be specified. By default, or if 0 is specified, all available threads are used. ```python from cogent3 import load_aligned_seqs from piqtree import jc_distances aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") # Use only 4 threads distance_matrix = jc_distances(aln, num_threads=4) ``` ## See also - For using the JC distance matrix to construct a rapid neighbour-joining tree, see ["Construct a rapid neighbour-joining tree from a distance matrix"](construct_nj_tree.md). iqtree-piqtree-b8a3d6a/docs/quickstart/calculate_rf_distances.md000066400000000000000000000016241521173175100252770ustar00rootroot00000000000000# Calculate pairwise Robinson-Foulds distances between trees A pairwise Robinson-Foulds distance matrix can be constructed from a sequence of cogent3 tree objects using [`robinson_foulds`](../api/tree_distance/robinson_foulds.md). ## Usage ### Basic Usage Construct a collection of cogent3 tree objects, then use [`robinson_foulds`](../api/tree_distance/robinson_foulds.md) to find the pairwise distances. ```python from cogent3 import make_tree from piqtree import robinson_foulds tree1 = make_tree("(a,b,(c,(d,e)));") tree2 = make_tree("(e,b,(c,(d,a)));") tree3 = make_tree("(a,b,(d,(c,e)));") rf_distances = robinson_foulds([tree1, tree2, tree3]) ``` ## See also - For constructing a maximum likelihood tree, see ["Construct a maximum likelihood phylogenetic tree"](construct_ml_tree.md). - For making a random phylogenetic tree, see ["Make a randomly generated phylogenetic tree"](make_random_tree.md). iqtree-piqtree-b8a3d6a/docs/quickstart/construct_consensus_tree.md000066400000000000000000000056711521173175100257670ustar00rootroot00000000000000# Construct a consensus tree from a collection of trees A consensus tree can be constructed from a collection of `cogent3` tree objects with [`consensus_tree`](../api/tree/consensus_tree.md). The method defaults to the majority-rule consensus tree - though different minimum levels of support can be used to achieve the strict consensus tree, and extended majority-rule consensus tree. By default, the support values of the input trees are carried over onto the consensus tree (see [Bootstrap values](#bootstrap-values) below). ## Usage ### Majority-rule consensus tree From a collection of trees, the majority-rule consensus tree can be constructed. ```python from cogent3 import make_tree from piqtree import consensus_tree tree1 = make_tree("(a,(b,(c,(d,e))));") tree2 = make_tree("(a,((b,c),(d,e)));") tree3 = make_tree("(a,((b,d),(c,e)));") tree = consensus_tree([tree1, tree2, tree3]) # (a,(b,c,(d,e))); ``` ### Strict consensus tree The `min_support` parameter can be set to 1.0 to construct a strict consensus tree (only the clades that appear in all of the trees). The parameter represents the proportion of trees a clade must appear in to be in the resulting tree. ```python from cogent3 import make_tree from piqtree import consensus_tree tree1 = make_tree("(a,(b,(c,(d,e))));") tree2 = make_tree("(a,((b,c),(d,e)));") tree3 = make_tree("(a,((b,d),(c,e)));") tree = consensus_tree([tree1, tree2, tree3], min_support=1.0) # (a,(b,c,d,e)); ``` ### Extended majority-rule consensus tree When the `min_support` parameter is equal to 0, the extended majority-rule consensus tree is computed. ```python from cogent3 import make_tree from piqtree import consensus_tree tree1 = make_tree("(a,(b,(c,(d,e))));") tree2 = make_tree("(a,((b,c),(d,e)));") tree3 = make_tree("(a,((b,c),(d,e)));") tree4 = make_tree("(a,(c,(b,(d,e))));") tree5 = make_tree("(c,(b,(a,(d,e))));") tree = consensus_tree([tree1, tree2, tree3, tree4, tree5], min_support=0) # (a,((b,c),(d,e))); ``` ### Bootstrap values When the input trees carry their own branch support - for example, the ultrafast bootstrap support produced by [`build_tree`](construct_ml_tree.md) - `consensus_tree` carries these values over onto the matching clades of the consensus tree, averaged across the input trees that contain each clade. The way the values are combined is set by `support_aggregate` (`"mean"` by default, or `"max"` / `"min"`), and each node's value can be accessed from `#!py3 node.support`. ```python from cogent3 import make_tree from piqtree import consensus_tree # the numbers on the internal nodes are each tree's own bootstrap support tree1 = make_tree("(a,((b,c)96,(d,e)90));") tree2 = make_tree("(a,((b,c)88,(d,e)70));") tree = consensus_tree([tree1, tree2]) # support_aggregate="mean" by default # (b,c) -> mean(96, 88) -> 92.0 # (d,e) -> mean(90, 70) -> 80.0 ``` ## See also - For making a random phylogenetic tree, see ["Make a randomly generated phylogenetic tree"](make_random_tree.md). iqtree-piqtree-b8a3d6a/docs/quickstart/construct_ml_tree.md000066400000000000000000000052571521173175100243570ustar00rootroot00000000000000# Construct a maximum likelihood phylogenetic tree A maximum-likelihood phylogenetic tree can be constructed from cogent3 alignment objects using [`build_tree`](../api/tree/build_tree.md). ## Usage ### Basic Usage Construct a `cogent3` alignment object, then construct a maximum-likelihood tree. ```python from cogent3 import load_aligned_seqs from piqtree import build_tree aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") tree = build_tree(aln, "GTR") log_likelihood = tree.params["lnL"] ``` ### Ultrafast Bootstrap To perform ultrafast bootstrapping, the number of replicates can be specified. The number of replicates must be at least 1000. The support for each node in the tree object can be accessed from `#!py3 node.support`. ```python from cogent3 import load_aligned_seqs from piqtree import build_tree aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") tree = build_tree(aln, "K81+FO", bootstrap_replicates=2000) ``` ### Reproducible Results For reproducible results, a random seed may be specified. > **Caution:** 0 is a specific random seed. None is equivalent to no random seed being specified. ```python from cogent3 import load_aligned_seqs from piqtree import build_tree aln = load_aligned_seqs("my_protein.fasta", moltype="protein") tree = build_tree(aln, "Dayhoff", rand_seed=3) ``` ### Multithreading To speed up computation, the number of threads to be used may be specified. By default, the computation is done on a single thread. If 0 is specified, then IQ-TREE attempts to determine the optimal number of threads. > **Caution:** If 0 is specified with small datasets, the time to determine the > optimal number of threads may exceed the time to find the maximum likelihood > tree. ```python from cogent3 import load_aligned_seqs from piqtree import build_tree aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") model = "HKY+I+G6" tree = build_tree(aln, model, num_threads=4) ``` ### Additional options Additional options in the format that would be passed to the IQ-TREE CLI can be set. Options in `other_options` already allowed through `build_tree` will be ignored. ```python from cogent3 import load_aligned_seqs from piqtree import build_tree aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") tree = build_tree(aln, "GTR", other_options="--epsilon 0.1 -n 0") ``` ## See also - For how to specify a `Model`, see ["Use different kinds of substitution models"](using_substitution_models.md). - For selecting the best `Model`, see ["Find the model of best fit with ModelFinder"](using_model_finder.md). - For fitting branch lengths to a tree topology, see ["Fit branch lengths to a tree topology from an alignment"](fit_tree_topology.md). iqtree-piqtree-b8a3d6a/docs/quickstart/construct_nj_tree.md000066400000000000000000000023571521173175100243540ustar00rootroot00000000000000# Construct a rapid neighbour-joining tree from a distance matrix A rapid neighbour-joining tree can be constructed from a pairwise `DistanceMatrix` object with [`nj_tree`](../api/tree/nj_tree.md). ## Usage ### Basic Usage Make a pairwise distance matrix, then construct the rapid neighbour-joining tree. ```python from cogent3 import load_aligned_seqs from piqtree import jc_distances, nj_tree aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") distance_matrix = jc_distances(aln) tree = nj_tree(distance_matrix) ``` ### Other Distance Matrices `cogent3` supports the calculation of **paralinear**, **JC69**, **TN93**, **hamming** and **pdist** distance matrices from alignment objects. ```python from cogent3 import load_aligned_seqs from piqtree import nj_tree aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") distance_matrix = aln.distance_matrix(calc="TN93") # calc is not case sensitive tree = nj_tree(distance_matrix) ``` ## See also - For constructing the JC distance matrix with `piqtree`, see ["Construct a rapid neighbour-joining tree from a distance matrix"](calculate_jc_distances.md). - For constructing a maximum likelihood tree, see ["Construct a maximum likelihood phylogenetic tree"](construct_ml_tree.md). iqtree-piqtree-b8a3d6a/docs/quickstart/fit_tree_topology.md000066400000000000000000000052041521173175100243510ustar00rootroot00000000000000# Fit branch lengths to a tree topology from an alignment Branch lengths can be fitted to a tree from a cogent3 alignment object using [`fit_tree`](../api/tree/fit_tree.md). ## Usage ### Basic Usage Construct `cogent3` alignment and tree objects, then fit branch lengths to a new tree. ```python from cogent3 import load_aligned_seqs, make_tree from piqtree import fit_tree aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") tree = make_tree("((Human, Chimpanzee), Rhesus, Mouse);") fitted_tree = fit_tree(aln, tree, model="F81") log_likelihood = fitted_tree.params["lnL"] ``` ### Multithreading To speed up computation, the number of threads to be used may be specified. By default, the computation is done on a single thread. If 0 is specified, then IQ-TREE attempts to determine the optimal number of threads. > **Caution:** If 0 is specified with small datasets, the time to determine the > optimal number of threads may exceed the time to find the maximum likelihood > tree. ```python from cogent3 import load_aligned_seqs, make_tree from piqtree import fit_tree aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") tree = make_tree("((Human, Chimpanzee), Rhesus, Mouse);") model = "HKY+I+R3" fitted_tree = fit_tree(aln, tree, model, num_threads=4) ``` ### Fixed branch lengths The likelihood for a tree with specified branch lengths may be calculated by using the `bl_fixed` argument. When set to True, specified branch lengths are not optimised and the likelihood for the tree is calculated. Any unspecified branch lengths will still be optimised. ```python from cogent3 import load_aligned_seqs, make_tree from piqtree import fit_tree aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") tree = make_tree("((Human:0.1, Chimpanzee:0.15):0.2, Rhesus:0.3, Mouse:0.5);") tree_with_likelihood = fit_tree(aln, tree, model="GTR", bl_fixed=True) log_likelihood = tree_with_likelihood.params["lnL"] ``` ### Additional options Additional options in the format that would be passed to the IQ-TREE CLI can be set. Options in `other_options` already allowed through `fit_tree` will be ignored. ```python from cogent3 import load_aligned_seqs, make_tree from piqtree import fit_tree aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") tree = make_tree("((Human, Chimpanzee), Rhesus, Mouse);") fitted_tree = fit_tree(aln, tree, model="GTR", other_options="-blmin 0.001 -blmax 1.5") ``` ## See also - For how to specify a `Model`, see ["Use different kinds of substitution models"](using_substitution_models.md). - For constructing a maximum likelihood tree, see ["Construct a maximum likelihood phylogenetic tree"](construct_ml_tree.md). iqtree-piqtree-b8a3d6a/docs/quickstart/index.md000066400000000000000000000023171521173175100217250ustar00rootroot00000000000000# Quickstart Want to jump right in to using `piqtree`? This is the place to be! Here, you can find examples to: - [Construct a maximum likelihood phylogenetic tree.](construct_ml_tree.md) - [Fit branch lengths to a tree topology from an alignment.](fit_tree_topology.md) - [Simulate alignments with AliSim.](simulate_alignment.md) - [Use different kinds of substitution models.](using_substitution_models.md) - [Find the model of best fit with ModelFinder.](using_model_finder.md) - [Calculate pairwise Jukes-Cantor distances.](calculate_jc_distances.md) - [Construct a rapid neighbour-joining tree from a distance matrix.](construct_nj_tree.md) - [Construct a consensus tree from a collection of trees.](construct_consensus_tree.md) - [Make a randomly generated phylogenetic tree.](make_random_tree.md) - [Calculate pairwise Robinson-Foulds distances between trees.](calculate_rf_distances.md) - [Display substitution models.](available_submodels.py) - [Display frequency options.](available_frequency_options.py) - [Display rate-heterogeneity options.](available_rate_heterogeneity_options.py) - [Using the `piqtree` `cogent3` apps.](../apps/index.md) Be sure to check out the [API Reference](../api/index.md) for full usage! iqtree-piqtree-b8a3d6a/docs/quickstart/make_random_tree.md000066400000000000000000000026621521173175100241150ustar00rootroot00000000000000# Make a randomly generated phylogenetic tree A randomly generated phylogenetic tree can be made using [`random_tree`](../api/tree/random_tree.md#piqtree.random_tree). Multiple tree generation modes are supported with the [`TreeGenMode`](../api/tree/random_tree.md#piqtree.TreeGenMode) including balanced, birth-death, caterpillar, star, uniform, and Yule-Harding tree. ## Usage ### Basic Usage Specify the number of taxa, and under what method the tree is to be generated. See the documentation for [`TreeGenMode`](../api/tree/random_tree.md#piqtree.TreeGenMode) for all available generation options. > **Note:** if star trees are generated the tree appears bifurcating, but branch lengths are set to zero where appropriate. ```python from piqtree import TreeGenMode, random_tree num_taxa = 100 tree = random_tree(num_taxa, TreeGenMode.YULE_HARDING) ``` ### Reproducible Results For reproducible results, a random seed may be specified. > **Caution:** 0 is a specific random seed. None is equivalent to no random seed being specified. ```python from piqtree import TreeGenMode, random_tree num_taxa = 100 tree = random_tree(num_taxa, TreeGenMode.CATERPILLAR, rand_seed=1) ``` ## See also - For constructing a maximum likelihood tree, see ["Construct a maximum likelihood phylogenetic tree"](construct_ml_tree.md). - For constructing a consensus tree, see ["Construct a consensus tree from a collection of trees"](construct_consensus_tree.md).iqtree-piqtree-b8a3d6a/docs/quickstart/simulate_alignment.md000066400000000000000000000030241521173175100244730ustar00rootroot00000000000000# Simulate alignments with AliSim An alignment can be simulated over a cogent3 tree object using [`simulate_alignment`](../api/alignment/simulate_alignment.md). ## Usage ### Basic Usage Construct a `cogent3` tree object, then simulate an alignment over it. ```python from cogent3 import make_tree from piqtree import simulate_alignment tree = make_tree("(A:0.3544,(B:0.1905,C:0.1328):0.0998,D:0.0898);") aln = simulate_alignment(tree, "JC") ``` ### Reproducible Results For reproducible results, a random seed may be specified. > **Caution:** 0 is a specific random seed. None is equivalent to no random seed being specified. ```python from cogent3 import make_tree from piqtree import simulate_alignment tree = make_tree("(A:0.3544,(B:0.1905,C:0.1328):0.0998,D:0.0898);") aln = simulate_alignment(tree, "Dayhoff", rand_seed=42) ``` ### Multithreading To speed up computation, the number of threads to be used may be specified. By default, the computation is done on a single thread. If 0 is specified, then IQ-TREE automatically determines the optimal number of threads. ```python from cogent3 import make_tree from piqtree import simulate_alignment tree = make_tree("(A:0.3544,(B:0.1905,C:0.1328):0.0998,D:0.0898);") aln = simulate_alignment(tree, "JC", length=10000, num_threads=0) ``` ## See also - For how to specify a `Model`, see ["Use different kinds of substitution models"](using_substitution_models.md). - For constructing a maximum likelihood tree, see ["Construct a maximum likelihood phylogenetic tree"](construct_ml_tree.md).iqtree-piqtree-b8a3d6a/docs/quickstart/using_model_finder.md000066400000000000000000000063071521173175100244550ustar00rootroot00000000000000# Find the model of best fit with ModelFinder IQ-TREE's ModelFinder can be used to automatically find the model of best fit for an alignment using [`model_finder`](../api/model/model_finder.md). The best scoring model under either **the *Akaike information criterion* (AIC), *corrected Akaike information criterion* (AICc), or the *Bayesian information criterion* (BIC) can be selected. ## Usage ### Basic Usage Construct a `cogent3` alignment object, then construct a maximum-likelihood tree. ```python from cogent3 import load_aligned_seqs from piqtree import model_finder aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") result = model_finder(aln) best_aic_model = result.best_aic best_aicc_model = result.best_aicc best_bic_model = result.best_bic ``` ### Specifying the Search Space We expose the `mset`, `mfreq` and `mrate` parameters from IQ-TREE's ModelFinder to specify the substitution model search space, base frequency search space, and rate heterogeneity search space respectively. They can be specified as a set of strings in either `model_set`, `freq_set` or `rate_set` respectively. ```python from cogent3 import load_aligned_seqs from piqtree import model_finder aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") result = model_finder(aln, model_set={"HKY", "TIM"}) best_aic_model = result.best_aic best_aicc_model = result.best_aicc best_bic_model = result.best_bic ``` ### Reproducible Results For reproducible results, a random seed may be specified. > **Caution:** 0 is a specific random seed. None is equivalent to no random seed being specified. ```python from cogent3 import load_aligned_seqs from piqtree import model_finder aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") result = model_finder(aln, rand_seed=5) best_aic_model = result.best_aic best_aicc_model = result.best_aicc best_bic_model = result.best_bic ``` ### Multithreading To speed up computation, the number of threads to be used may be specified. By default, the computation is done on a single thread. If 0 is specified, then IQ-TREE attempts to determine the optimal number of threads. > **Caution:** If 0 is specified with small datasets, the time to determine the > optimal number of threads may exceed the time to find the maximum likelihood > tree. ```python from cogent3 import load_aligned_seqs from piqtree import model_finder aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") result = model_finder(aln, num_threads=4) best_aic_model = result.best_aic best_aicc_model = result.best_aicc best_bic_model = result.best_bic ``` ### Additional options Additional options in the format that would be passed to the IQ-TREE CLI can be set. Options in `other_options` already allowed through `model_finder` will be ignored. ```python from cogent3 import load_aligned_seqs from piqtree import model_finder aln = load_aligned_seqs("my_alignment.fasta", moltype="dna") result = model_finder(aln, model_set={"HKY", "TIM"}, other_options="-mtree") ``` ## See also - For constructing a maximum likelihood tree, see ["Construct a maximum likelihood phylogenetic tree"](construct_ml_tree.md). - For how to specify a `Model`, see ["Use different kinds of substitution models"](using_substitution_models.md). iqtree-piqtree-b8a3d6a/docs/quickstart/using_substitution_models.md000066400000000000000000000163671521173175100261540ustar00rootroot00000000000000# Use different kinds of substitution models piqtree currently supports all named IQ-TREE DNA models including Lie Markov models, empirical amino-acid exchange rate matrices, as well as specification for base frequencies and rate heterogeneity across sites. We use the [`Model`](../api/model/Model.md) class to represent the substitution model which can be constructed from strings, or using enums. Most functions can already compute this directly from the passed model string, so usage of [`make_model`](../api/model/make_model.md) may be preferable. Substitution models can be combined with specification for base frequencies, and rate heterogeneity across sites models. ## Usage ### Standard DNA Models DNA models may be specified using the [`StandardDnaModel`](../api/model/SubstitutionModel.md#piqtree.model.StandardDnaModel) enum, or by using the IQ-TREE string representation. A full list of supported DNA models is available [here](../api/model/SubstitutionModel.md#piqtree.model.StandardDnaModel). ```python from piqtree import Model from piqtree.model import StandardDnaModel hky_model_1 = Model("HKY") hky_model_2 = Model(StandardDnaModel.HKY) ``` #### Parameterisation of Standard DNA Models IQ-TREE allows DNA models to be parameterised by specifying relative substitution rates. See the [IQ-TREE documentation](https://iqtree.github.io/doc/Substitution-Models) for the precise definition of the parameters for the chosen model. ```python from piqtree import Model from piqtree.model import StandardDnaModel model = Model("GTR{1.0,2.0,1.5,3.7,2.8}") model = Model(StandardDnaModel.GTR([1.0, 2.0, 1.5, 3.7, 2.8])) ``` ### Lie Markov Models Lie Markov models may be specified using the [`LieModel`](../api/model/SubstitutionModel.md#piqtree.model.LieModel) enum, or by using the IQ-TREE string representation. A full list of supported DNA models is available [here](../api/model/SubstitutionModel.md#piqtree.model.LieModel). The pairing prefix may also be specified - RY for purine-pyrimidine pairing (default); WS for weak-strong pairing; and MK aMino-Keto pairing. ```python from piqtree import Model from piqtree.model import LieModel lie_ws_6_6_model_1 = Model("WS6.6") lie_ws_6_6_model_2 = Model(LieModel.LIE_6_6("WS")) lie_12_12_model_1 = Model("12.12") lie_12_12_model_2 = Model(LieModel.LIE_12_12) ``` #### Parameterisation of Lie Markov Models IQ-TREE supports the parameterisation of Lie Markov models. The first number (before the period) corresponds to the number of basis matrices used by the model. The first basis matrix is unparameterised, and the parameters refer to the weights (bounded between -0.98 and 0.98 exclusive) of the remaining basis matrices of the model. ```python from piqtree import Model from piqtree.model import LieModel model = Model("MK3.3b{0.3,-0.5}") model = Model(LieModel.LIE_3_3b("MK", [0.3, -0.5])) ``` ### Amino-acid Models Amino-acid models may be specified using the [`AaModel`](../api/model/SubstitutionModel.md#piqtree.model.AaModel) enum, or by using the IQ-TREE string representation. A full list of supported amino-acid models is available [here](../api/model/SubstitutionModel.md#piqtree.model.AaModel). ```python from piqtree import Model from piqtree.model import AaModel dayhoff_model_1 = Model("Dayhoff") dayhoff_model_2 = Model(AaModel.Dayhoff) nq_yeast_model_1 = Model("NQ.yeast") nq_yeast_model_2 = Model(AaModel.NQ_yeast) ``` ### Base Frequencies Three types of base frequencies can be specified using the [`FreqType`](../api/model/FreqType.md) enum, or alternatively the [`CustomBaseFreq`](../api/model/FreqType.md) class can be used to fix base frequencies. Otherwise, the IQ-TREE string representation can be used. If base frequencies are not specified, the chosen model's default settings are used. - [`F`](../api/model/FreqType.md#piqtree.model.FreqType.F): Empirical base frequencies. String representation also used to fix base frequencies. - [`FQ`](../api/model/FreqType.md#piqtree.model.FreqType.FQ): Equal base frequencies. - [`FO`](../api/model/FreqType.md#piqtree.model.FreqType.FO): Optimised base frequencies by maximum-likelihood. ```python from piqtree import Model from piqtree.model import CustomBaseFreq, FreqType # Default for the GTR model empirical_freqs_1 = Model("GTR", freq_type="F") empirical_freqs_2 = Model("GTR", freq_type=FreqType.F) equal_freqs_1 = Model("GTR", freq_type="FQ") equal_freqs_2 = Model("GTR", freq_type=FreqType.FQ) opt_freqs_1 = Model("GTR", freq_type="FO") opt_freqs_2 = Model("GTR", freq_type=FreqType.FO) custom_freqs_1 = Model("GTR", freq_type="F{0.1,0.2,0.3,0.4}") custom_freqs_2 = Model("GTR", freq_type=CustomBaseFreq([0.1, 0.2, 0.3, 0.4])) ``` ### Rate Heterogeneity #### Invariable Sites A boolean flag can be specified when constructing the [`Model`](../api/model/Model.md) class to allow for a proportion of invariable sites. To fix the proportion of invariable sites, a float representing the proportion can be used instead. ```python from piqtree import Model without_invar_sites = Model("TIM", invariable_sites=False) # Default with_invar_sites = Model("TIM", invariable_sites=True) prop_invar = Model("TIM", invariable_sites=0.1) ``` #### Discrete Gamma Model We support the [`DiscreteGammaModel`](../api/model/RateModel.md#piqtree.model.DiscreteGammaModel) allowing for a variable number of rate categories (by default 4). The Gamma shape parameter (alpha) can also be set. ```python from piqtree import Model from piqtree.model import DiscreteGammaModel # 4 rate categories, no invariable sites k81_discrete_gamma_4 = Model("K81", rate_model=DiscreteGammaModel()) # 8 rate categories, with invariable sites k81_invar_discrete_gamma_8 = Model("K81", rate_model=DiscreteGammaModel(8), invariable_sites=True) # 4 rate categories, alpha=0.2 k81_alpha = Model("K81", rate_model=DiscreteGammaModel(alpha=0.2)) ``` #### FreeRate Model We support the [`FreeRateModel`](../api/model/RateModel.md#piqtree.model.FreeRateModel) allowing for a variable number of rate categories (by default 4). The FreeRate weights for each of the rate categories and the corresponding rates may also be fixed. ```python from piqtree import Model from piqtree.model import FreeRateModel # 4 rate categories, no invariable sites sym_free_rate_4 = Model("SYM", rate_model=FreeRateModel()) # 8 rate categories, with invariable sites sym_invar_free_rate_8 = Model("SYM", rate_model=FreeRateModel(8), invariable_sites=True) # 2 rate categories with specified weights and rates sym_free_rate_parameterised = Model("SYM", rate_model=FreeRateModel(2, weights=[0.2, 0.8], rates=[2.5, 0.625])) ``` ### Making Model Classes from IQ-TREE Strings For the supported model types, the Model class can be created by using [`make_model`](../api/model/make_model.md) on the IQ-TREE string representation of the model. ```python from piqtree import make_model model = make_model("GTR+FQ+I+R3") ``` ## See also - Use a [`Model`](../api/model/Model.md) to construct a maximum likelihood tree: ["Construct a maximum likelihood phylogenetic tree"](construct_ml_tree.md). - Use a [`Model`](../api/model/Model.md) to fit branch lengths to a tree topology: ["Fit branch lengths to a tree topology from an alignment"](fit_tree_topology.md). - Use a [`Model`](../api/model/Model.md) to simulate an alignment with AliSim: ["Simulate alignments with AliSim"](simulate_alignment.md). iqtree-piqtree-b8a3d6a/docs/scripts/000077500000000000000000000000001521173175100175665ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/docs/scripts/prepare_doc_test_data.py000066400000000000000000000013651521173175100244600ustar00rootroot00000000000000from pathlib import Path from cogent3 import load_aligned_seqs PROJECT_ROOT = Path(__file__) while PROJECT_ROOT.name != "docs": PROJECT_ROOT = PROJECT_ROOT.parent PROJECT_ROOT = PROJECT_ROOT.parent def prepare_my_alignment() -> None: aln = load_aligned_seqs(PROJECT_ROOT / "tests/data/example.fasta", moltype="dna") aln = aln.take_seqs(["Human", "Chimpanzee", "Rhesus", "Mouse"]) aln.write("my_alignment.fasta") def prepare_protein_alignment() -> None: aln = load_aligned_seqs( PROJECT_ROOT / "tests/data/protein.fasta", moltype="protein", ) aln = aln.take_seqs(sorted(aln.names)[:4]) aln.write("my_protein.fasta") if __name__ == "__main__": prepare_my_alignment() prepare_protein_alignment() iqtree-piqtree-b8a3d6a/iqtree3/000077500000000000000000000000001521173175100165235ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/mkdocs.yml000066400000000000000000000061741521173175100171620ustar00rootroot00000000000000site_name: piqtree site_url: "https://github.com/iqtree/piqtree" site_author: "Gavin Huttley" repo_url: "https://github.com/iqtree/piqtree" repo_name: 'GitHub' exclude_docs: | scripts/* theme: name: material features: - navigation.indexes highlightjs: true hljs_languages: - yaml - python - text markdown_extensions: - pymdownx.highlight: anchor_linenums: true line_spans: __span pygments_lang_class: true - pymdownx.inlinehilite - pymdownx.snippets - pymdownx.superfences plugins: - search - mkdocstrings: handlers: python: paths: [src] options: show_root_heading: true docstring_style: numpy docstring_section_style: spacy docstring_options: ignore_init_summary: true merge_init_into_class: true - mkdocs-jupyter: allow_errors: false include_requirejs: true execute: true remove_tag_config: remove_input_tags: - hide_code nav: - Introduction: index.md - Quickstart: - quickstart/index.md - quickstart/construct_ml_tree.md - quickstart/fit_tree_topology.md - quickstart/simulate_alignment.md - quickstart/using_substitution_models.md - quickstart/using_model_finder.md - quickstart/calculate_jc_distances.md - quickstart/construct_nj_tree.md - quickstart/construct_consensus_tree.md - quickstart/make_random_tree.md - quickstart/calculate_rf_distances.md - Available substitution models: quickstart/available_submodels.py - Available state frequency options: quickstart/available_frequency_options.py - Available rate-heterogeneity options: quickstart/available_rate_heterogeneity_options.py - Apps: - apps/index.md - The available piqtree apps: apps/available_help.py - Selecting models for phylogenetic analysis: apps/model_finder.py - Estimate a phylogenetic tree: apps/phylo.py - Fit a model to one tree: apps/fit_tree.py - Pairwise JC distances: apps/pairwise_dist.py - NJ tree: apps/nj.py - Parallel processing across alignments: apps/app_pipeline.py - API reference: - api/index.md - Trees: - api/tree/build_tree.md - api/tree/fit_tree.md - api/tree/nj_tree.md - api/tree/consensus_tree.md - api/tree/random_tree.md - Alignments: - api/alignment/simulate_alignment.md - Substitution models: - api/model/model_finder.md - api/model/ModelFinderResult.md - api/model/Model.md - api/model/make_model.md - api/model/SubstitutionModel.md - api/model/FreqType.md - api/model/RateModel.md - Genetic distances: - api/genetic_distance/jc_distances.md - Tree distances: - api/tree_distance/robinson_foulds.md - Contributing: - developers/index.md - developers/environment_setup.md - developers/iqtree_submodule.md - developers/contributing.md - developers/testing.md - developers/troubleshooting.md - developers/release.md - Citation: citation.md iqtree-piqtree-b8a3d6a/noxfile.py000066400000000000000000000034141521173175100171670ustar00rootroot00000000000000import os import tempfile from pathlib import Path import nox _py_versions = range(12, 15) _python_sessions = [f"3.{v}" for v in _py_versions] @nox.session(python=_python_sessions) def test(session: nox.Session) -> None: posargs = list(session.posargs) env = os.environ.copy() install_spec = "-e.[test]" session.install(install_spec) session.run("pytest", *posargs, env=env) @nox.session(python=_python_sessions) def type_check(session: nox.Session) -> None: posargs = list(session.posargs) env = os.environ.copy() install_spec = ".[typing]" session.install(install_spec) session.run("mypy", "src", "tests", *posargs, env=env) @nox.session(python=_python_sessions) def ruff(session: nox.Session) -> None: posargs = list(session.posargs) env = os.environ.copy() install_spec = ".[lint]" session.install(install_spec) session.run("ruff", "check", *posargs, env=env) @nox.session(python=_python_sessions) def test_docs(session: nox.Session) -> None: doc_md_files = [path.resolve() for path in Path("docs").rglob("*.md")] doc_py_files = [path.resolve() for path in Path("docs").rglob("*.py")] doctest_setup_path = Path("docs/scripts/prepare_doc_test_data.py").resolve() posargs: list[str | Path] = list(session.posargs) posargs.extend(["--markdown-docs", *doc_md_files]) env = os.environ.copy() install_spec = ".[test]" session.install(install_spec) with tempfile.TemporaryDirectory() as tmpdir: session.chdir(tmpdir) session.run("python", doctest_setup_path, env=env) session.run("pytest", *posargs, env=env) session.install("cogent3[extra]", "diverse-seq") for py_file in doc_py_files: session.run("python", py_file, env=env, silent=True) iqtree-piqtree-b8a3d6a/pyproject.toml000066400000000000000000000141701521173175100200660ustar00rootroot00000000000000[build-system] requires = ["setuptools>=61.0", "pybind11==3.0.4", "delvewheel==1.13.0"] build-backend = "setuptools.build_meta" [project] name = "piqtree" dependencies = [ "citeable>=2026.3.11b0", "cogent3>=2026.4.20a0", "pyyaml", "requests", ] requires-python = ">=3.12" authors = [ { name = "Gavin Huttley" }, { name = "Robert McArthur" }, { name = "Bui Quang Minh " }, { name = "Richard Morris" }, { name = "Thomas Wong" }, ] description = "Python bindings for IQTree" readme = "README.md" dynamic = ["version"] license = "GPL-2.0-only" license-files = ["LICENSE"] classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Science/Research", "Topic :: Scientific/Engineering :: Bio-Informatics", "Topic :: Software Development :: Libraries :: Python Modules", "Natural Language :: English", "Operating System :: Microsoft :: Windows", "Operating System :: MacOS", "Operating System :: POSIX :: Linux", "Programming Language :: C++", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Typing :: Typed", ] [project.urls] Repository = "https://github.com/cogent3/piqtree" Documentation = "https://piqtree.readthedocs.io" [project.optional-dependencies] dev = [ "cibuildwheel==4.0.0", "pybind11==3.0.4", "delvewheel==1.13.0", "scriv", "piqtree[test]", "piqtree[lint]", "piqtree[typing]", ] test = ["pytest", "pytest-cov", "pytest-markdown-docs", "pytest-mock", "nox"] lint = ["ruff==0.15.16"] typing = ["mypy==2.1.0", "piqtree[stubs]", "piqtree[test]"] stubs = ["types-PyYAML", "types-requests"] extra = ["cogent3[extra]"] doc = [ "mkdocs", "mkdocstrings[python]", "mkdocs-jupyter", "pymdown-extensions", "jupytext", "piqtree[test]", "cogent3[extra]", "diverse-seq>=2025.7.10", "jupyter", "ipywidgets", ] [project.entry-points."cogent3.app"] piq_build_tree = "piqtree._app:piq_build_tree" piq_fit_tree = "piqtree._app:piq_fit_tree" piq_random_tree = "piqtree._app:piq_random_tree" piq_jc_distances = "piqtree._app:piq_jc_distances" piq_nj_tree = "piqtree._app:piq_nj_tree" piq_model_finder = "piqtree._app:piq_model_finder" piq_consensus_tree = "piqtree._app:piq_consensus_tree" piq_simulate_alignment = "piqtree._app:piq_simulate_alignment" [project.entry-points."cogent3.hook"] quick_tree = "piqtree._app:piq_nj_tree" [tool.setuptools.dynamic] version = { attr = "piqtree.__version__" } [tool.ruff] exclude = [ "iqtree3", ".bzr", ".direnv", ".eggs", ".git", ".git-rewrite", ".hg", ".ipynb_checkpoints", ".mypy_cache", ".nox", ".pants.d", ".pyenv", ".pytest_cache", ".pytype", ".ruff_cache", ".svn", ".tox", ".venv", ".vscode", "__pypackages__", "_build", "buck-out", "build", "dist", "node_modules", "site-packages", "venv", ] # Same as Black. line-length = 88 indent-width = 4 target-version = "py312" [tool.ruff.lint] # Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default. # Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or # McCabe complexity (`C901`) by default. select = ["ALL"] ignore = [ "EXE002", # don't require shebang "E501", # allow long lines where appropriate "PLC0415", # allow imports inside functions "PLR0913", # allow many arguments "PLR2004", # allow magic value comparisons "D", # doc linting rules ] # Allow fix for all enabled rules (when `--fix`) is provided. fixable = ["ALL"] unfixable = [] # Allow unused variables when underscore-prefixed. dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" [tool.ruff.lint.per-file-ignores] "tests/**/*.py" = [ "S101", # asserts allowed in tests... "INP001", # __init__.py files are not required... "N802", # allow non snake_case function names for fixtures "N803", # allow use of fixture constants "SLF001", # private member access is useful for testing "FBT001", # allow bool pos args for parameterisation "D", # don't require docstring linting ] "docs/**/*.py" = ["B018", "E402", "ERA001", "INP001", "D"] "src/piqtree/_app/__init__.py" = [ "N801", # apps follow function naming convention ] "src/piqtree/__init__.py" = [ "E402", # handle DLLs before imports "PTH118", # os operations for DLL path "PTH120", # os operations for DLL path ] "src/piqtree/model/_substitution_model.py" = [ "N815", # use IQ-TREE naming scheme ] "setup.py" = [ "S603", # allow subprocess invalidated input for brew install "S607", # allow subprocess with partial path "D", # Don't expect docstrings for setup.py ] "noxfile.py" = [ "D", # Don't expect docstrings for noxfile ] "rtd_get_docs.py" = [ "D", # Don't expect docstrings for rtd file. ] [tool.ruff.format] # Like Black, use double quotes for strings. quote-style = "double" # Like Black, indent with spaces, rather than tabs. indent-style = "space" # Like Black, respect magic trailing commas. skip-magic-trailing-comma = false # Like Black, automatically detect the appropriate line ending. line-ending = "auto" # Enable auto-formatting of code examples in docstrings. Markdown, # reStructuredText code/literal blocks and doctests are all supported. # # This is currently disabled by default, but it is planned for this # to be opt-out in the future. docstring-code-format = false # Set the line length limit used when formatting code snippets in # docstrings. # # This only has an effect when the `docstring-code-format` setting is # enabled. docstring-code-line-length = "dynamic" [tool.scriv] format = "md" categories = [ "Contributors", "ENH", "BUG", "API", "DOC", "Deprecations", "Discontinued", ] output_file = "changelog.md" version = "literal: src/piqtree/__init__.py: __version__" skip_fragments = "README.*" new_fragment_template = "file: changelog.d/templates/new.md.j2" entry_title_template = "file: changelog.d/templates/title.md.j2" [[tool.mypy.overrides]] module = ['cogent3.*', "_piqtree"] ignore_missing_imports = true iqtree-piqtree-b8a3d6a/rtd_get_docs.py000066400000000000000000000064701521173175100201700ustar00rootroot00000000000000# this file # is directly used by .readthedocs.yaml # it extracts the built docs from the github artefact # created by the build_docs.yml github action import os import pathlib import time import zipfile import requests MAX_WAIT_TIME = 600 # Typically takes 5.5 minutes POLL_INTERVAL = 20 def get_rtd_version_name() -> str: return os.environ.get("READTHEDOCS_VERSION_NAME", "").lower() def get_github_token() -> str: token = os.environ.get("GITHUB_TOKEN") if token is None: token = os.environ.get("GITHUB_TOKEN_PRIVATE") if not token: msg = "GitHub token not found." raise OSError(msg) return token def get_latest_run(workflow_filename: str, headers: dict) -> dict: url = f"https://api.github.com/repos/iqtree/piqtree/actions/workflows/{workflow_filename}/runs" response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() runs = response.json()["workflow_runs"] if not runs: msg = f"No workflow runs found for: '{workflow_filename}'" raise ValueError(msg) return runs[0] def wait_for_run_completion(run: dict, headers: dict) -> dict: run_id = run["id"] run_url = f"https://api.github.com/repos/iqtree/piqtree/actions/runs/{run_id}" waited = 0 while waited < MAX_WAIT_TIME: response = requests.get(run_url, headers=headers, timeout=10) response.raise_for_status() run_status = response.json() status = run_status["status"] conclusion = run_status["conclusion"] if status == "completed": if conclusion != "success": msg = f"Latest workflow run failed with conclusion: '{conclusion}'" raise RuntimeError(msg) return run_status time.sleep(POLL_INTERVAL) waited += POLL_INTERVAL msg = "Timed out waiting for workflow run to complete." raise TimeoutError(msg) def download_and_extract_artifact(run: dict, headers: dict) -> None: artifact_name = "piqtree-docs-html" artifacts_url = run["artifacts_url"] response = requests.get(artifacts_url, headers=headers, timeout=10) response.raise_for_status() artifacts = response.json()["artifacts"] artifact = next((a for a in artifacts if a["name"] == artifact_name), None) if artifact is None: msg = f"Artifact '{artifact_name}' not found in the run." raise ValueError(msg) download_url = artifact["archive_download_url"] response = requests.get(download_url, headers=headers, timeout=10) response.raise_for_status() out = pathlib.Path(f"{artifact_name}.zip") out.write_bytes(response.content) with zipfile.ZipFile(out, "r") as zip_ref: zip_ref.extractall("_readthedocs/html/") def download_and_extract_docs() -> None: version = get_rtd_version_name() if version not in ("latest", "stable"): msg = f"Unexpected version '{version}' for readthedocs." raise ValueError(msg) workflow_filename = "release.yml" if version == "stable" else "build_docs.yml" headers = {"Authorization": f"token {get_github_token()}"} latest_run = get_latest_run(workflow_filename, headers) completed_run = wait_for_run_completion(latest_run, headers) download_and_extract_artifact(completed_run, headers) if __name__ == "__main__": download_and_extract_docs() iqtree-piqtree-b8a3d6a/setup.py000066400000000000000000000052511521173175100166640ustar00rootroot00000000000000"""setup for piqtree.""" import platform import subprocess from pathlib import Path from pybind11.setup_helpers import Pybind11Extension, build_ext from setuptools import setup LIBRARY_DIR = "src/piqtree/_libiqtree/" IQTREE_LIB_NAME = "iqtree" def get_brew_prefix(package: str) -> Path: """Get the prefix path for a specific Homebrew package.""" return Path( subprocess.check_output(["brew", "--prefix", package]).strip().decode("utf-8"), ) extra_libs = [] extra_compile_args = [] include_dirs = [] library_dirs = [] def include_dlls() -> None: import shutil from delvewheel._dll_utils import get_all_needed needed_dll_paths, _, _, _ = get_all_needed( LIBRARY_DIR + f"{IQTREE_LIB_NAME}.dll", set(), None, "raise", False, # noqa: FBT003 False, # noqa: FBT003 ) for dll_path in needed_dll_paths: shutil.copy(dll_path, LIBRARY_DIR) def setup_windows() -> None: include_dlls() def setup_macos() -> None: brew_prefix_llvm = get_brew_prefix("llvm") brew_prefix_libomp = get_brew_prefix("libomp") # Define OpenMP flags and libraries for macOS extra_compile_args.extend(["-Xpreprocessor", "-fopenmp"]) extra_libs.extend(["z", "omp"]) # Use the paths from Homebrew for libomp include_dirs.extend([str(brew_prefix_libomp / "include")]) library_dirs.extend( [ str(brew_prefix_libomp / "lib"), str(brew_prefix_llvm / "lib"), ], ) def setup_linux() -> None: extra_compile_args.extend(["-fopenmp"]) extra_libs.extend(["z", "gomp"]) match system := platform.system(): case "Windows": setup_windows() case "Darwin": setup_macos() case "Linux": setup_linux() case _: msg = f"Unsupported platform: {system}" raise ValueError(msg) ext_modules = [ Pybind11Extension( "_piqtree", ["src/piqtree/_libiqtree/_piqtree.cpp"], library_dirs=[ *library_dirs, LIBRARY_DIR, ], libraries=[IQTREE_LIB_NAME, *extra_libs], extra_compile_args=extra_compile_args, include_dirs=include_dirs, ), ] class StripBuildExt(build_ext): def run(self) -> None: super().run() system = platform.system() flag = "-x" if system == "Darwin" else "--strip-unneeded" for ext in self.extensions: ext_path = self.get_ext_fullpath(ext.name) subprocess.run(["strip", flag, ext_path], check=True) setup( name="piqtree", ext_modules=ext_modules, cmdclass={"build_ext": StripBuildExt}, zip_safe=False, package_data={"piqtree": ["_libiqtree/*.dll"]}, ) iqtree-piqtree-b8a3d6a/src/000077500000000000000000000000001521173175100157365ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/src/piqtree/000077500000000000000000000000001521173175100174075ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/src/piqtree/__init__.py000066400000000000000000000023151521173175100215210ustar00rootroot00000000000000"""piqtree - access the power of IQ-TREE within Python.""" def _add_dll_path() -> None: import os if "add_dll_directory" in dir(os): dll_folder = os.path.join(os.path.dirname(__file__), "_libiqtree") os.add_dll_directory(dll_folder) # type: ignore[attr-defined] _add_dll_path() del _add_dll_path from _piqtree import __iqtree_version__ from piqtree._data import dataset_names, download_dataset from piqtree.iqtree import ( ModelFinderResult, TreeGenMode, build_tree, consensus_tree, fit_tree, jc_distances, model_finder, nj_tree, random_tree, robinson_foulds, simulate_alignment, ) from piqtree.model import ( Model, available_freq_type, available_models, available_rate_type, make_model, ) __version__ = "0.8.3" __all__ = [ "Model", "ModelFinderResult", "TreeGenMode", "__iqtree_version__", "available_freq_type", "available_models", "available_rate_type", "build_tree", "consensus_tree", "dataset_names", "download_dataset", "fit_tree", "jc_distances", "make_model", "model_finder", "nj_tree", "random_tree", "robinson_foulds", "simulate_alignment", ] iqtree-piqtree-b8a3d6a/src/piqtree/_app/000077500000000000000000000000001521173175100203265ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/src/piqtree/_app/__init__.py000066400000000000000000000116661521173175100224510ustar00rootroot00000000000000"""cogent3 apps for piqtree.""" from collections.abc import Iterable from cogent3.core.alignment import Alignment from cogent3.core.tree import PhyloNode from cogent3.evolve.fast_distance import DistanceMatrix from scinexus import composable from scinexus.misc import extend_docstring_from from piqtree import ( TreeGenMode, build_tree, consensus_tree, fit_tree, jc_distances, model_finder, nj_tree, random_tree, simulate_alignment, ) from piqtree._cite import cite_piqtree from piqtree.distribution import IndelDistribution from piqtree.iqtree import ModelFinderResult from piqtree.model import Model @composable.define_app(cite=cite_piqtree) class piq_build_tree: @extend_docstring_from(build_tree) def __init__( self, model: Model | str, *, rand_seed: int | None = None, bootstrap_reps: int | None = None, num_threads: int | None = None, other_options: str = "", ) -> None: self._model = model self._rand_seed = rand_seed self._bootstrap_reps = bootstrap_reps self._num_threads = num_threads self._other_options = other_options def main( self, aln: Alignment, ) -> PhyloNode: tree = build_tree( aln, self._model, self._rand_seed, bootstrap_replicates=self._bootstrap_reps, num_threads=self._num_threads, other_options=self._other_options, ) tree.source = getattr(aln, "source", None) return tree @composable.define_app(cite=cite_piqtree) class piq_fit_tree: @extend_docstring_from(fit_tree) def __init__( self, tree: PhyloNode, model: Model | str, *, num_threads: int | None = None, other_options: str = "", bl_fixed: bool = False, ) -> None: self._tree = tree self._model = model self._num_threads = num_threads self._bl_fixed = bl_fixed self._other_options = other_options def main( self, aln: Alignment, ) -> PhyloNode: tree = fit_tree( aln, self._tree, self._model, self._num_threads, other_options=self._other_options, bl_fixed=self._bl_fixed, ) tree.source = getattr(aln, "source", None) return tree @composable.define_app(cite=cite_piqtree) @extend_docstring_from(random_tree) def piq_random_tree( num_taxa: int, tree_mode: TreeGenMode, rand_seed: int | None = None, ) -> PhyloNode: return random_tree(num_taxa, tree_mode, rand_seed) @composable.define_app(cite=cite_piqtree) class piq_jc_distances: @extend_docstring_from(jc_distances) def __init__( self, num_threads: int | None = None, ) -> None: self._num_threads = num_threads def main( self, aln: Alignment, ) -> DistanceMatrix: dists = jc_distances( aln, num_threads=self._num_threads, ) dists.source = getattr(aln, "source", None) return dists @composable.define_app(cite=cite_piqtree) @extend_docstring_from(nj_tree) def piq_nj_tree( dists: DistanceMatrix, *, allow_negative: bool = False, ) -> PhyloNode: tree = nj_tree(dists, allow_negative=allow_negative) tree.params |= {"provenance": "piqtree"} tree.source = getattr(dists, "source", None) return tree @composable.define_app(cite=cite_piqtree) @extend_docstring_from(model_finder) def piq_model_finder( aln: Alignment, ) -> ModelFinderResult: return model_finder(aln) @composable.define_app(cite=cite_piqtree) @extend_docstring_from(consensus_tree) def piq_consensus_tree( trees: Iterable[PhyloNode], *, min_support: float = 0.5, ) -> PhyloNode: return consensus_tree(trees, min_support=min_support) @composable.define_app(cite=cite_piqtree) @extend_docstring_from(simulate_alignment) def piq_simulate_alignment( tree: PhyloNode, model: Model | str, length: int = 1000, rand_seed: int | None = None, insertion_rate: float = 0.0, deletion_rate: float = 0.0, insertion_size_distribution: IndelDistribution | str = "POW{1.7/100}", deletion_size_distribution: IndelDistribution | str = "POW{1.7/100}", root_seq: str | None = None, num_threads: int | None = None, ) -> Alignment: return simulate_alignment( tree, model, length=length, rand_seed=rand_seed, insertion_rate=insertion_rate, deletion_rate=deletion_rate, insertion_size_distribution=insertion_size_distribution, deletion_size_distribution=deletion_size_distribution, root_seq=root_seq, num_threads=num_threads, ) _ALL_APP_NAMES = [ "piq_build_tree", "piq_fit_tree", "piq_random_tree", "piq_jc_distances", "piq_nj_tree", "piq_model_finder", "piq_consensus_tree", "piq_simulate_alignment", ] iqtree-piqtree-b8a3d6a/src/piqtree/_cite.py000066400000000000000000000011231521173175100210410ustar00rootroot00000000000000from citeable import Article cite_piqtree = Article( key="piqtree", author=[ "McArthur, Robert Neil", "Wong, Thomas King-Fung", "Lang, Yapeng", "Morris, Richard Andrew", "Caley, Katherine", "Mallawaarachchi, Vijini", "Minh, Bui Quang", "Huttley, Gavin", ], title="{piqtree}: A Python Package for Seamless Phylogenetic Inference with {IQ-TREE}", year=2026, journal="Molecular Biology and Evolution", pages="msag061", doi="10.1093/molbev/msag061", url="https://doi.org/10.1093/molbev/msag061", ) iqtree-piqtree-b8a3d6a/src/piqtree/_data.py000066400000000000000000000044351521173175100210370ustar00rootroot00000000000000import pathlib import zipfile import requests _data_files = { "mammal-orths.zip": "https://github.com/user-attachments/files/17806562/mammal-orths.zip", "brca1.fasta.gz": "https://github.com/user-attachments/files/17806563/brca1.fasta.gz", "example.phy.gz": "https://github.com/user-attachments/files/17806561/example.phy.gz", "example.tree.gz": "https://github.com/user-attachments/files/17821150/example.tree.gz", } def _inflate_zip(zip_path: pathlib.Path, output_dir: pathlib.Path) -> pathlib.Path: """Decompress the contents of a zip file to a named directory.""" with zipfile.ZipFile(zip_path, "r") as zip_ref: zip_ref.extractall(output_dir) return output_dir def _get_url(name: str) -> str: """URL for a data file.""" if name not in _data_files: msg = f"Unknown data file: {name}" raise ValueError(msg) return _data_files[name] def dataset_names() -> list[str]: """Return the names of available datasets.""" return list(_data_files.keys()) def download_dataset( name: str, dest_dir: str | pathlib.Path, dest_name: str | None = None, *, inflate_zip: bool = True, ) -> pathlib.Path: """Download data files used in docs, requires an internet connection. Parameters ---------- name : str Data set name, see `dataset_names()`. dest_dir : str | pathlib.Path Where to write a local copy. dest_name : str | None, optional Name of the file to write, if None (default) uses name. inflate_zip : bool, optional Whether to unzip archives, by default True. Returns ------- pathlib.Path Path to the downloaded file Notes ----- Only downloads if dest_dir / dest_name does not exist. """ dest_dir = pathlib.Path(dest_dir) url = _get_url(name) dest_name = dest_name or name outpath = dest_dir / dest_name outpath.parent.mkdir(parents=True, exist_ok=True) if outpath.exists(): return outpath response = requests.get(url, stream=True, timeout=20) block_size = 4096 with outpath.open("wb") as out: for data in response.iter_content(block_size): out.write(data) if inflate_zip and outpath.suffix == ".zip": outpath = _inflate_zip(outpath, dest_dir) return outpath iqtree-piqtree-b8a3d6a/src/piqtree/_libiqtree/000077500000000000000000000000001521173175100215265ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/src/piqtree/_libiqtree/README.txt000066400000000000000000000001031521173175100232160ustar00rootroot00000000000000Place the IQ-TREE static library, `libiqtree.a`, in this directory.iqtree-piqtree-b8a3d6a/src/piqtree/_libiqtree/_piqtree.cpp000066400000000000000000000125771521173175100240560ustar00rootroot00000000000000#include "_piqtree.h" #include #include #include #include #include #include #include "_piqtree.h" namespace py = pybind11; void checkError(char* errorStr) { if (errorStr && std::strlen(errorStr) > 0) { string msg(errorStr); iqtree_free(errorStr); throw std::runtime_error(msg); } if (errorStr) iqtree_free(errorStr); } namespace PYBIND11_NAMESPACE { namespace detail { template <> struct type_caster { public: PYBIND11_TYPE_CASTER(StringArray, const_name("StringArray")); // Conversion from Python to C++ bool load(handle src, bool) { /* Extract PyObject from handle */ PyObject* source = src.ptr(); if (!py::isinstance(source)) { return false; } auto seq = reinterpret_borrow(src); value.length = seq.size(); tmpStrings.reserve(value.length); tmpCStrs.reserve(value.length); for (size_t i = 0; i < seq.size(); ++i) { auto item = seq[i]; if (!py::isinstance(item)) { return false; } tmpStrings.push_back(item.cast()); tmpCStrs.push_back(tmpStrings[i].c_str()); } value.strings = tmpCStrs.data(); return true; } // Conversion from C++ to Python static handle cast(StringArray src, return_value_policy, handle) { throw std::runtime_error("Unsupported operation"); } private: vector tmpStrings; vector tmpCStrs; }; template <> struct type_caster { public: PYBIND11_TYPE_CASTER(DoubleArray, _("DoubleArray")); // Conversion from Python to C++ bool load(handle src, bool) { if (!py::isinstance>(src)) { return false; // Only accept numpy arrays of float64 } auto arr = py::cast>(src); if (arr.ndim() != 1) { return false; // Only accept 1D arrays } value.length = arr.size(); tmpDoubles.assign(arr.data(), arr.data() + value.length); value.doubles = tmpDoubles.data(); return true; } // Conversion from C++ to Python static handle cast(DoubleArray src, return_value_policy, handle) { throw std::runtime_error("Unsupported operation"); } private: vector tmpDoubles; }; template <> struct type_caster { public: PYBIND11_TYPE_CASTER(IntegerResult, _("IntegerResult")); // Conversion from Python to C++ bool load(handle /* src */, bool /* convert */) { throw std::runtime_error("Unsupported operation"); } // Conversion from C++ to Python static handle cast(const IntegerResult& src, return_value_policy, handle) { checkError(src.errorStr); return py::int_(src.value).release(); } }; template <> struct type_caster { public: // Indicate that this caster only supports conversion from C++ to Python PYBIND11_TYPE_CASTER(StringResult, _("StringResult")); // Reject Python to C++ conversion bool load(handle src, bool) { throw std::runtime_error("Unsupported operation"); } // Conversion from C++ to Python static handle cast(const StringResult& src, return_value_policy, handle) { checkError(src.errorStr); PyObject* py_str = PyUnicode_FromString(src.value); if (!py_str) throw error_already_set(); iqtree_free(src.value); return handle(py_str); } }; template <> struct type_caster { public: PYBIND11_TYPE_CASTER(DoubleArrayResult, _("DoubleArrayResult")); // Conversion from Python to C++ bool load(handle src, bool) { throw std::runtime_error("Unsupported operation"); } // Conversion from C++ to Python static handle cast(DoubleArrayResult src, return_value_policy, handle) { checkError(src.errorStr); auto result = py::array_t(src.length); std::memcpy(result.mutable_data(), src.value, src.length * sizeof(double)); iqtree_free(src.value); return result.release(); } }; } // namespace detail } // namespace PYBIND11_NAMESPACE int mine() { return 42; } PYBIND11_MODULE(_piqtree, m) { m.doc() = "_piqtree - Linking IQ-TREE to Python!"; m.attr("__iqtree_version__") = version(); m.def("iq_robinson_fould", &robinson_fould, "Calculates the robinson fould distance between two trees"); m.def("iq_random_tree", &random_tree, "Generates a set of random phylogenetic trees. tree_gen_mode " "allows:\"YULE_HARDING\", \"UNIFORM\", \"CATERPILLAR\", \"BALANCED\", " "\"BIRTH_DEATH\", \"STAR_TREE\"."); m.def("iq_build_tree", &build_tree, "Perform phylogenetic analysis on the input alignment (in string " "format). With estimation of the best topology."); m.def("iq_fit_tree", &fit_tree, "Perform phylogenetic analysis on the input alignment (in string " "format). With restriction to the input toplogy."); m.def("iq_model_finder", &modelfinder, "Find optimal model for an alignment."); m.def("iq_jc_distances", &build_distmatrix, "Construct pairwise distance matrix for alignment."); m.def("iq_nj_tree", &build_njtree, "Build neighbour-joining tree from distance matrix."); m.def("iq_consensus_tree", &consensus_tree, "Compute a consensus tree from a sequence of trees."); m.def("iq_simulate_alignment", &simulate_alignment, "Simulate an alignment with AliSim."); m.def("mine", &mine, "The meaning of life, the universe (and everything)!"); } iqtree-piqtree-b8a3d6a/src/piqtree/_libiqtree/_piqtree.h000066400000000000000000000135701521173175100235150ustar00rootroot00000000000000#ifndef _PIQTREE_H #define _PIQTREE_H #include #include using namespace std; #ifdef _MSC_VER #pragma pack(push, 1) #else #pragma pack(1) #endif typedef struct { const char** strings; size_t length; } StringArray; typedef struct { double* doubles; size_t length; } DoubleArray; typedef struct { int value; char* errorStr; } IntegerResult; typedef struct { char* value; char* errorStr; } StringResult; typedef struct { double* value; size_t length; char* errorStr; } DoubleArrayResult; #ifdef _MSC_VER #pragma pack(pop) #else #pragma pack() #endif /* * Calculates the robinson fould distance between two trees */ extern "C" IntegerResult robinson_fould(const char* ctree1, const char* ctree2); /* * Generates a set of random phylogenetic trees * tree_gen_mode allows:"YULE_HARDING", "UNIFORM", "CATERPILLAR", "BALANCED", * "BIRTH_DEATH", "STAR_TREE" output: a newick tree (in string format) */ extern "C" StringResult random_tree(int num_taxa, const char* tree_gen_mode, int num_trees, int rand_seed = 0); /* * Perform phylogenetic analysis on the input alignment * With estimation of the best topology * num_thres -- number of cpu threads to be used, default: 1; 0 - auto detection * of the optimal number of cpu threads output: results in YAML format with the * tree and the details of parameters */ extern "C" StringResult build_tree(StringArray& names, StringArray& seqs, const char* model, int rand_seed = 0, int bootstrap_rep = 0, int num_thres = 1, const char* other_options = NULL); /* * Perform phylogenetic analysis on the input alignment * With restriction to the input toplogy * blfix -- whether to fix the branch length as those on the given tree, * default: false num_thres -- number of cpu threads to be used, default: 1; 0 - * auto detection of the optimal number of cpu threads output: results in YAML * format with the details of parameters */ extern "C" StringResult fit_tree(StringArray& names, StringArray& seqs, const char* model, const char* intree, bool blfix = false, int rand_seed = 0, int num_thres = 1, const char* other_options = NULL); /* * Perform phylogenetic analysis with ModelFinder * on the input alignment (in string format) * model_set -- a set of models to consider * freq_set -- a set of frequency types * rate_set -- a set of RHAS models * rand_seed -- random seed, if 0, then will generate a new random seed * num_thres -- number of cpu threads to be used, default: 1; 0 - auto detection * of the optimal number of cpu threads output: modelfinder results in YAML * format */ extern "C" StringResult modelfinder(StringArray& names, StringArray& seqs, int rand_seed = 0, const char* model_set = "", const char* freq_set = "", const char* rate_set = "", int num_thres = 1, const char* other_options = NULL); /* * Build pairwise JC distance matrix * output: set of distances * (n * i + j)-th element of the list represents the distance between i-th and * j-th sequence, where n is the number of sequences num_thres -- number of cpu * threads to be used, default: 1; 0 - use all available cpu threads on the * machine */ extern "C" DoubleArrayResult build_distmatrix(StringArray& names, StringArray& seqs, int num_thres = 1); /* * Using Rapid-NJ to build tree from a distance matrix * output: a newick tree (in string format) */ extern "C" StringResult build_njtree(StringArray& names, DoubleArray& distances); /* * Compute a consensus tree * trees -- a set of input trees * minsup -- a threshold to build the majority consensus (default: 0.5) * output -- the resulting consensus tree */ extern "C" StringResult consensus_tree(StringArray& trees, double minsup = 0.5); /* * Execute AliSim Simulation * output: results in YAML format that contains the simulated alignment and the * content of the log file tree -- the NEWICK tree string subst_model -- the * substitution model name seed -- the random seed partition_info -- partition * information partition_type -- partition type is either ‘equal’, ‘proportion’, * or ‘unlinked’ seq_length -- the length of sequences insertion_rate -- the * insertion rate deletion_rate -- the deletion rate root_seq -- the root * sequence num_threads -- the number of threads insertion_size_distribution -- * the insertion size distribution deletion_size_distribution -- the deletion * size distribution population_size -- the population size */ extern "C" StringResult simulate_alignment( const char* tree, const char* subst_model, int seed, const char* partition_info = "", const char* partition_type = "", int seq_length = 1000, double insertion_rate = 0, double deletion_rate = 0, const char* root_seq = "", int num_threads = 1, const char* insertion_size_distribution = "", const char* deletion_size_distribution = "", int population_size = -1); /* * version number */ extern "C" StringResult version(); /* * Free memory allocated by IQ-TREE */ extern "C" void iqtree_free(void* p); #endif /* _PIQTREE_H */ iqtree-piqtree-b8a3d6a/src/piqtree/distribution/000077500000000000000000000000001521173175100221265ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/src/piqtree/distribution/__init__.py000066400000000000000000000004251521173175100242400ustar00rootroot00000000000000from .indel_distribution import ( IndelDistribution, IndelGeometric, IndelLavalette, IndelNegativeBinomial, IndelZipfian, ) __all__ = [ "IndelDistribution", "IndelGeometric", "IndelLavalette", "IndelNegativeBinomial", "IndelZipfian", ] iqtree-piqtree-b8a3d6a/src/piqtree/distribution/indel_distribution.py000066400000000000000000000022041521173175100263700ustar00rootroot00000000000000from abc import ABC, abstractmethod class IndelDistribution(ABC): @abstractmethod def iqtree_str(self) -> str: pass # pragma: no cover def __str__(self) -> str: return self.iqtree_str() class IndelZipfian(IndelDistribution): def __init__(self, exponent: float, max_size: int) -> None: self.exponent = exponent self.max_size = max_size def iqtree_str(self) -> str: return f"POW{{{self.exponent}/{self.max_size}}}" class IndelGeometric(IndelDistribution): def __init__(self, mean: float) -> None: self.mean = mean def iqtree_str(self) -> str: return f"GEO{{{self.mean}}}" class IndelNegativeBinomial(IndelDistribution): def __init__(self, mean: float, variance: float) -> None: self.mean = mean self.variance = variance def iqtree_str(self) -> str: return f"NB{{{self.mean}/{self.variance}}}" class IndelLavalette(IndelDistribution): def __init__(self, a: float, max_size: int) -> None: self.a = a self.max_size = max_size def iqtree_str(self) -> str: return f"LAV{{{self.a}/{self.max_size}}}" iqtree-piqtree-b8a3d6a/src/piqtree/exceptions.py000066400000000000000000000003171521173175100221430ustar00rootroot00000000000000"""Contains piqtree exceptions.""" class IqTreeError(Exception): """An error thrown by IQ-TREE.""" class ParseIqTreeError(Exception): """There was an error when parsing a result from IQ-TREE.""" iqtree-piqtree-b8a3d6a/src/piqtree/iqtree/000077500000000000000000000000001521173175100207005ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/src/piqtree/iqtree/__init__.py000066400000000000000000000011721521173175100230120ustar00rootroot00000000000000"""Functions for calling IQ-TREE as a library.""" from ._alignment import simulate_alignment from ._jc_distance import jc_distances from ._model_finder import ModelFinderResult, ModelResultValue, model_finder from ._random_tree import TreeGenMode, random_tree from ._robinson_foulds import robinson_foulds from ._tree import build_tree, consensus_tree, fit_tree, nj_tree __all__ = [ "ModelFinderResult", "ModelResultValue", "TreeGenMode", "build_tree", "consensus_tree", "fit_tree", "jc_distances", "model_finder", "nj_tree", "random_tree", "robinson_foulds", "simulate_alignment", ] iqtree-piqtree-b8a3d6a/src/piqtree/iqtree/_alignment.py000066400000000000000000000106571521173175100234000ustar00rootroot00000000000000from typing import cast import yaml from _piqtree import iq_simulate_alignment from cogent3 import make_aligned_seqs from cogent3.core.alignment import Alignment from cogent3.core.tree import PhyloNode from piqtree.distribution import IndelDistribution from piqtree.exceptions import ParseIqTreeError from piqtree.iqtree._decorator import iqtree_func from piqtree.model import LieModel, Model, make_model from piqtree.util import get_newick, make_rand_seed iq_simulate_alignment = iqtree_func(iq_simulate_alignment, hide_files=True) UNSUPPORTED_MODELS = { LieModel.LIE_1_1, LieModel.LIE_3_3a, LieModel.LIE_4_4a, LieModel.LIE_6_7a, LieModel.LIE_9_20a, LieModel.LIE_9_20b, LieModel.LIE_12_12, } def simulate_alignment( tree: PhyloNode, model: Model | str, length: int = 1000, rand_seed: int | None = None, insertion_rate: float = 0.0, deletion_rate: float = 0.0, insertion_size_distribution: IndelDistribution | str = "POW{1.7/100}", deletion_size_distribution: IndelDistribution | str = "POW{1.7/100}", root_seq: str | None = None, num_threads: int | None = None, ) -> Alignment: """Uses AliSim to simulate an Alignment through IQ-TREE. Parameters ---------- tree: list[cogent3.PhyloNode] A tree to simulate an alignment over. model: str The substitution model's specification. length: int The length of the alignment (by default 1000). Alignment may be longer when indel model is used due to insertion events. rand_seed : int | None, optional The random seed - None means no seed is used, by default None. insertion_rate: float | None, optional The insertion rate relative to substitution rate (by default 0.0). deletion_rate: float | None, optional The deletion rate relative to substitution rate (by default 0.0). insertion_size_distribution: str | None, optional The insertion size distribution (by default the Zipfian distribution with a=1.7 and maximum size 100). deletion_size_distribution: str | None, optional The deletion size distribution (by default the Zipfian distribution with a=1.7 and maximum size 100). root_seq: str | None, optional The root sequence (by default None). num_threads: int | None, optional Number of threads for IQ-TREE to use, by default None (single-threaded). Returns ------- c3_types.AlignedSeqsType The simulated alignment. """ if rand_seed is None: rand_seed = make_rand_seed() if root_seq is None: root_seq = "" if num_threads is None: num_threads = 1 if isinstance(model, str): model = make_model(model) if model.submod_type.base_model in UNSUPPORTED_MODELS: msg = f"Lie Model {cast('LieModel', model.submod_type.base_model).value} is unsupported." raise ValueError(msg) newick_tree = get_newick(tree) yaml_result = yaml.safe_load( iq_simulate_alignment( newick_tree, str(model), rand_seed, "", "", length, insertion_rate, deletion_rate, root_seq, num_threads, str(insertion_size_distribution), str(deletion_size_distribution), -1, ), ) seqs = _parse_yaml_alignment(yaml_result["alignment"]) return make_aligned_seqs(seqs, moltype=model.submod_type.get_moltype()) def _parse_yaml_alignment(yaml_alignment: str) -> dict[str, str]: seqs: dict[str, str] = {} name = None seq_buffer = None for part in yaml_alignment.split("\n"): if part.startswith(">"): if seq_buffer is not None: if name is None: msg = "Got sequence data without name." # pragma: no cover raise ParseIqTreeError(msg) # pragma: no cover seqs[name] = seq_buffer name = part.strip()[1:] seq_buffer = "" elif seq_buffer is not None: seq_buffer += part.strip() else: msg = f"Unexpected parsed value '{part}'" # pragma: no cover raise ParseIqTreeError(msg) # pragma: no cover if seq_buffer is not None: if name is None: msg = "Got sequence data without name." # pragma: no cover raise ParseIqTreeError(msg) # pragma: no cover seqs[name] = seq_buffer return seqs iqtree-piqtree-b8a3d6a/src/piqtree/iqtree/_decorator.py000066400000000000000000000060051521173175100233740ustar00rootroot00000000000000"""Decorators for IQ-TREE functions.""" import io import os import pathlib import sys import tempfile from collections.abc import Callable from functools import wraps from piqtree.exceptions import IqTreeError def _fd_or_fallback(stream: object, fallback_fd: int) -> int: """Return the file descriptor for the stream, or a fallback file descriptor. Parameters ---------- stream : stdout or stderr stream The io stream. fallback_fd : int Fallback file descriptor. Returns ------- int The file descriptor for the stream, or the fallback on error. """ try: return stream.fileno() # type: ignore[attr-defined] except io.UnsupportedOperation: # pragma: no cover return fallback_fd # pragma: no cover def iqtree_func[**Param, RetType]( func: Callable[Param, RetType], *, hide_files: bool = False, ) -> Callable[Param, RetType]: """IQ-TREE function wrapper. Hides stdout and stderr, as well as any output files. Parameters ---------- func : Callable[Param, RetType] The IQ-TREE library function. hide_files : bool, optional Whether hiding output files is necessary, by default False. Returns ------- Callable[Param, RetType] The wrapped IQ-TREE function. Raises ------ IqTreeError An error from the IQ-TREE library. """ @wraps(func) def wrapper_iqtree_func(*args: Param.args, **kwargs: Param.kwargs) -> RetType: # Flush stdout and stderr sys.stdout.flush() sys.stderr.flush() # Fetch file descriptors out_fd = _fd_or_fallback(sys.stdout, 1) err_fd = _fd_or_fallback(sys.stderr, 2) # Save original stdout and stderr file descriptors saved_stdout_fd = os.dup(out_fd) saved_stderr_fd = os.dup(err_fd) # Open /dev/null (or NUL on Windows) as destination for stdout and stderr devnull_fd = os.open(os.devnull, os.O_WRONLY) if hide_files: original_dir = pathlib.Path.cwd() tempdir = tempfile.TemporaryDirectory(prefix=f"piqtree_{func.__name__}") os.chdir(tempdir.name) try: # Replace stdout and stderr with /dev/null os.dup2(devnull_fd, out_fd) os.dup2(devnull_fd, err_fd) # Call the wrapped function return func(*args, **kwargs) except RuntimeError as e: raise IqTreeError(e) from None finally: # Flush stdout and stderr sys.stdout.flush() sys.stderr.flush() # Restore stdout and stderr os.dup2(saved_stdout_fd, out_fd) os.dup2(saved_stderr_fd, err_fd) # Close the devnull file descriptor, and duplicated file descriptors os.close(devnull_fd) os.close(saved_stdout_fd) os.close(saved_stderr_fd) if hide_files: os.chdir(original_dir) tempdir.cleanup() return wrapper_iqtree_func iqtree-piqtree-b8a3d6a/src/piqtree/iqtree/_jc_distance.py000066400000000000000000000032711521173175100236620ustar00rootroot00000000000000from collections.abc import Sequence import numpy as np from _piqtree import iq_jc_distances from cogent3.core.alignment import Alignment from cogent3.evolve.fast_distance import DistanceMatrix from piqtree.iqtree._decorator import iqtree_func iq_jc_distances = iqtree_func(iq_jc_distances, hide_files=True) def _dists_to_distmatrix( distances: np.ndarray, names: Sequence[str], ) -> DistanceMatrix: """Convert numpy representation of distance matrix into cogent3 pairwise distance matrix. Parameters ---------- distances : np.ndarray Pairwise distances. names : Sequence[str] Corresponding sequence names. Returns ------- DistanceMatrix Pairwise distance matrix. """ dist_dict = {} for i in range(1, len(distances)): for j in range(i): dist_dict[(names[i], names[j])] = distances[i, j] return DistanceMatrix(dist_dict) def jc_distances( aln: Alignment, num_threads: int | None = None, ) -> DistanceMatrix: """Compute pairwise JC distances for a given alignment. Parameters ---------- aln : Alignment The alignment to compute pairwise JC distances for. num_threads: int | None, optional Number of threads for IQ-TREE to use, by default None (uses all available threads). Returns ------- DistanceMatrix Pairwise JC distance matrix. """ if num_threads is None: num_threads = 0 names = aln.names seqs = [str(seq) for seq in aln.iter_seqs(names)] distances = np.array(iq_jc_distances(names, seqs, num_threads)).reshape( (len(names), len(names)), ) return _dists_to_distmatrix(distances, names) iqtree-piqtree-b8a3d6a/src/piqtree/iqtree/_model_finder.py000066400000000000000000000143341521173175100240450ustar00rootroot00000000000000"""Python wrapper for model finder in the IQ-TREE library.""" import dataclasses from collections.abc import Iterable from typing import Any, cast import yaml from _piqtree import iq_model_finder from cogent3.core.alignment import Alignment from scinexus.misc import get_object_provenance from piqtree.iqtree._decorator import iqtree_func from piqtree.model import Model, make_model from piqtree.util import process_rand_seed_nonzero, validate_other_options iq_model_finder = iqtree_func(iq_model_finder, hide_files=True) @dataclasses.dataclass(slots=True, frozen=True) class ModelResultValue: """Model statistics from IQ-TREE model_finder. Parameters ---------- lnL : float Log likelihood of the model. nfp : int Number of free parameters in the model. tree_length : float Length of the tree (sum of branch lengths). """ lnL: float # noqa: N815 nfp: int tree_length: float @classmethod def from_string(cls, val: str) -> "ModelResultValue": """Parse the string produced by IQ-TREE model_finder for a given model.""" try: lnL, nfp, tree_length = val.split()[:3] # noqa: N806 return cls(lnL=float(lnL), nfp=int(nfp), tree_length=float(tree_length)) except ValueError as e: msg = f"Error parsing string '{val}'" raise ValueError(msg) from e @dataclasses.dataclass(slots=True) class ModelFinderResult: """Data returned by ModelFinder. Attributes ---------- source : str Source of the alignment. raw_data : dict[str, Any] Raw data returned by ModelFinder. best_aic : Model The best AIC model. best_aicc : Model The best AICc model. best_bic : Model The best BIC model. model_stats : dict[Model | str, ModelResultValue] Semi-processed representation of raw_data. """ source: str raw_data: dataclasses.InitVar[dict[str, Any]] best_aic: Model = dataclasses.field(init=False) best_aicc: Model = dataclasses.field(init=False) best_bic: Model = dataclasses.field(init=False) model_stats: dict[Model | str, ModelResultValue] = dataclasses.field( init=False, repr=False, default_factory=dict, ) def __post_init__(self, raw_data: dict[str, Any]) -> None: self.model_stats = { key: ModelResultValue.from_string(val) for key, val in raw_data.items() if not key.startswith(("best_", "initTree")) and isinstance(val, str) } self.best_aic = make_model(raw_data["best_model_AIC"]) self.best_aicc = make_model(raw_data["best_model_AICc"]) self.best_bic = make_model(raw_data["best_model_BIC"]) self.model_stats[self.best_aic] = ModelResultValue.from_string( raw_data[str(self.best_aic)], ) self.model_stats[self.best_aicc] = ModelResultValue.from_string( raw_data[str(self.best_aicc)], ) self.model_stats[self.best_bic] = ModelResultValue.from_string( raw_data[str(self.best_bic)], ) def to_rich_dict(self) -> dict[str, Any]: import piqtree result: dict[str, Any] = { "version": piqtree.__version__, "type": get_object_provenance(self), } raw_data = { str(model_): f"{stats.lnL} {stats.nfp} {stats.tree_length}" for model_, stats in self.model_stats.items() } for attr in ("best_model_AIC", "best_model_AICc", "best_model_BIC"): raw_data[attr] = str(getattr(self, attr.replace("_model", "").lower())) result["init_kwargs"] = {"raw_data": raw_data, "source": self.source} return result @classmethod def from_rich_dict(cls, data: dict[str, Any]) -> "ModelFinderResult": return cls(**data["init_kwargs"]) INVALID_MODEL_FINDER_PARAMS = [ "-s", # aln file "-m", # model selection "-mset", # model set "-mfreq", # freq set "-mrate", # rate set "-seed", # seed "-nt", # threads "-ntmax", # threads ] def model_finder( aln: Alignment, model_set: Iterable[str] | None = None, freq_set: Iterable[str] | None = None, rate_set: Iterable[str] | None = None, rand_seed: int | None = None, num_threads: int | None = None, other_options: str = "", ) -> ModelFinderResult: """Find the models of best fit for an alignment using ModelFinder. Parameters ---------- aln : Alignment The alignment to find the model of best fit for. model_set : Iterable[str] | None, optional Search space for models. Equivalent to IQ-TREE's mset parameter, by default None freq_set : Iterable[str] | None, optional Search space for frequency types. Equivalent to IQ-TREE's mfreq parameter, by default None rate_set : Iterable[str] | None, optional Search space for rate heterogeneity types. Equivalent to IQ-TREE's mrate parameter, by default None rand_seed : int | None, optional The random seed - None means no seed is used, by default None. num_threads: int | None, optional Number of threads for IQ-TREE to use, by default None (single-threaded). If 0 is specified, IQ-TREE attempts to find the optimal number of threads. other_options: str, optional Additional command line options for IQ-TREE. Returns ------- ModelFinderResult Collection of data returned from IQ-TREE's ModelFinder. """ validate_other_options(other_options, INVALID_MODEL_FINDER_PARAMS) source = cast("str", aln.info.source) rand_seed = process_rand_seed_nonzero(rand_seed) if num_threads is None: num_threads = 1 if model_set is None: model_set = set() if freq_set is None: freq_set = set() if rate_set is None: rate_set = set() names = aln.names seqs = [str(seq) for seq in aln.iter_seqs(names)] raw = yaml.safe_load( iq_model_finder( names, seqs, rand_seed, ",".join(model_set), ",".join(freq_set), ",".join(rate_set), num_threads, other_options, ), ) return ModelFinderResult(raw_data=raw, source=source) iqtree-piqtree-b8a3d6a/src/piqtree/iqtree/_parse_tree_parameters.py000066400000000000000000000147561521173175100260020ustar00rootroot00000000000000from typing import Any from cogent3.core.tree import PhyloNode from piqtree.exceptions import ParseIqTreeError from piqtree.model import Model, StandardDnaModel # the order defined in IQ-TREE # assume UNREST model has 12 rates, GTR and simpler models always have 6 rates present RATE_PARS = "A/C", "A/G", "A/T", "C/G", "C/T", "G/T" RATE_PARS_UNREST = ( "A/C", "A/G", "A/T", "C/A", "C/G", "C/T", "G/A", "G/C", "G/T", "T/A", "T/C", "T/G", ) MOTIF_PARS = "A", "C", "G", "T" def _insert_edge_pars(tree: PhyloNode, **kwargs: dict) -> None: # inserts the edge parameters into each edge to match the structure of # PhyloNode for node in tree.get_edge_vector(): # skip the rate parameters when node is the root if node.is_root(): kwargs = {k: v for k, v in kwargs.items() if k == "mprobs"} del node.params["edge_pars"] node.params.update(kwargs) def _edge_pars_for_cogent3(tree: PhyloNode, model: Model) -> None: base_model = model.submod_type.base_model rate_pars = tree.params["edge_pars"]["rates"] motif_pars = {"mprobs": tree.params["edge_pars"]["mprobs"]} # renames parameters to conform to cogent3's naming conventions if base_model in {StandardDnaModel.JC, StandardDnaModel.F81}: # skip rate_pars since rate parameters are constant in JC and F81 _insert_edge_pars( tree, **motif_pars, ) return if base_model in {StandardDnaModel.K80, StandardDnaModel.HKY}: rate_pars = {"kappa": rate_pars["A/G"]} elif base_model is StandardDnaModel.TN: rate_pars = {"kappa_r": rate_pars["A/G"], "kappa_y": rate_pars["C/T"]} elif base_model is StandardDnaModel.GTR: del rate_pars["G/T"] # applies global rate parameters to each edge _insert_edge_pars( tree, **rate_pars, **motif_pars, ) def _parse_nonlie_model(tree: PhyloNode, tree_yaml: dict) -> None: # parse motif and rate parameters in the tree_yaml for non-Lie DnaModel model_fits = tree_yaml.get("ModelDNA", {}) state_freq_str = model_fits.get("state_freq", "") rate_str = model_fits.get("rates", "") # parse motif parameters, assign each to a name, and raise an error if not found if state_freq_str: # converts the strings of motif parameters into dictionary state_freq_list = [ float(value) for value in state_freq_str.replace(" ", "").split(",") ] tree.params["edge_pars"] = { "mprobs": dict(zip(MOTIF_PARS, state_freq_list, strict=True)), } else: msg = "IQ-TREE output is malformed, motif parameters not found." raise ParseIqTreeError(msg) # parse rate parameters, assign each to a name, and raise an error if not found if rate_str: rate_list = [float(value) for value in rate_str.replace(" ", "").split(",")] tree.params["edge_pars"]["rates"] = dict( zip(RATE_PARS, rate_list, strict=True), ) else: msg = "IQ-TREE output is malformed, rate parameters not found." raise ParseIqTreeError(msg) def _parse_lie_model( tree: PhyloNode, tree_yaml: dict, lie_model_name: str, ) -> None: # parse motif and rate parameters in the tree_yaml for Lie DnaModel model_fits = tree_yaml.get(lie_model_name, {}) # parse motif parameters, assign each to a name, and raise an error if not found state_freq_str = model_fits.get("state_freq", "") if state_freq_str: state_freq_list = [ float(value) for value in state_freq_str.replace(" ", "").split(",") ] tree.params[lie_model_name] = { "mprobs": dict(zip(MOTIF_PARS, state_freq_list, strict=True)), } else: msg = "IQ-TREE output is malformed, motif parameters not found." raise ParseIqTreeError(msg) # parse rate parameters, skipping LIE_1_1 (aka JC69) since its rate parameter is constant thus absent if "model_parameters" in model_fits: model_parameters = model_fits["model_parameters"] # convert model parameters to a list of floats if they are a string if isinstance(model_parameters, str): tree.params[lie_model_name]["model_parameters"] = [ float(value) for value in model_parameters.replace(" ", "").split(",") ] else: # directly use the float tree.params[lie_model_name]["model_parameters"] = model_parameters def _parse_unrest_model(tree: PhyloNode, tree_yaml: dict) -> None: model_fits = tree_yaml.get("ModelUnrest", {}) state_freq_str = model_fits.get("state_freq", "") rate_str = model_fits.get("rates", "") # parse state frequencies if state_freq_str: state_freq_list = [ float(value) for value in state_freq_str.replace(" ", "").split(",") ] tree.params["edge_pars"] = { "mprobs": dict(zip(MOTIF_PARS, state_freq_list, strict=True)), } else: msg = "IQ-TREE output is malformed, motif parameters not found." # pragma: no cover raise ParseIqTreeError(msg) # pragma: no cover # parse rates if rate_str: rate_list = [float(value) for value in rate_str.replace(" ", "").split(",")] tree.params["edge_pars"]["rates"] = dict( zip(RATE_PARS_UNREST, rate_list, strict=True), ) else: msg = "IQ-TREE output is malformed, rate parameters not found." # pragma: no cover raise ParseIqTreeError(msg) # pragma: no cover def parse_model_parameters( tree: PhyloNode, tree_yaml: dict[str, Any], model: Model, ) -> None: """Parse model parameters from the returned yaml format. Parameters ---------- tree : PhyloNode The tree to attach model parameters to. tree_yaml : dict[str, Any] The yaml result returned from IQ-TREE. model : Model The model used. """ # parse non-Lie DnaModel parameters if "ModelDNA" in tree_yaml: _parse_nonlie_model(tree, tree_yaml) elif "ModelUnrest" in tree_yaml: _parse_unrest_model(tree, tree_yaml) # parse Lie DnaModel parameters, handling various Lie model names elif key := next( (key for key in tree_yaml if key.startswith("ModelLieMarkov")), None, ): _parse_lie_model(tree, tree_yaml, key) # for non-Lie models, populate parameters to each branch and # rename them to mimic PhyloNode if "edge_pars" in tree.params: _edge_pars_for_cogent3(tree, model) iqtree-piqtree-b8a3d6a/src/piqtree/iqtree/_random_tree.py000066400000000000000000000024121521173175100237070ustar00rootroot00000000000000"""Python wrappers to random tree generation in the IQ-TREE library.""" from enum import Enum, auto from _piqtree import iq_random_tree from cogent3 import make_tree from cogent3.core.tree import PhyloNode from piqtree.iqtree._decorator import iqtree_func from piqtree.util import process_rand_seed_nonzero iq_random_tree = iqtree_func(iq_random_tree) class TreeGenMode(Enum): """Setting under which to generate a random tree.""" YULE_HARDING = auto() UNIFORM = auto() CATERPILLAR = auto() BALANCED = auto() BIRTH_DEATH = auto() STAR_TREE = auto() def random_tree( num_taxa: int, tree_mode: TreeGenMode, rand_seed: int | None = None, ) -> PhyloNode: """Generate a random phylogenetic tree. Generates a random tree through IQ-TREE. Parameters ---------- num_taxa : int The number of taxa per tree. tree_mode : TreeGenMode How the tree is generated. rand_seed : int | None, optional The random seed - None means no seed is used, by default None. Returns ------- PhyloNode A random phylogenetic tree. """ rand_seed = process_rand_seed_nonzero(rand_seed) newick = iq_random_tree(num_taxa, tree_mode.name, 1, rand_seed).strip() return make_tree(newick) iqtree-piqtree-b8a3d6a/src/piqtree/iqtree/_robinson_foulds.py000066400000000000000000000022051521173175100246150ustar00rootroot00000000000000"""Python wrappers to RF distances in the IQ-TREE library.""" from collections.abc import Sequence import numpy as np from _piqtree import iq_robinson_fould from cogent3.core.tree import PhyloNode from piqtree.iqtree._decorator import iqtree_func from piqtree.util import get_newick iq_robinson_fould = iqtree_func(iq_robinson_fould) def robinson_foulds(trees: Sequence[PhyloNode]) -> np.ndarray: """Pairwise Robinson-Foulds distance between a sequence of trees. For the given collection of trees, returns a numpy array containing the pairwise distances between the trees. Parameters ---------- trees : Sequence[PhyloNode] The sequence of trees to calculate the pairwise Robinson-Foulds distances of. Returns ------- np.ndarray Pairwise Robinson-Foulds distances. """ pairwise_distances = np.zeros((len(trees), len(trees))) for i in range(1, len(trees)): for j in range(i): rf = iq_robinson_fould(get_newick(trees[i]), get_newick(trees[j])) pairwise_distances[i, j] = rf pairwise_distances[j, i] = rf return pairwise_distances iqtree-piqtree-b8a3d6a/src/piqtree/iqtree/_tree.py000066400000000000000000000272201521173175100223530ustar00rootroot00000000000000"""Python wrappers to tree searching functions in the IQ-TREE library.""" import statistics from collections.abc import Callable, Iterable, Sequence from typing import Any, cast import numpy as np import yaml from _piqtree import iq_build_tree, iq_consensus_tree, iq_fit_tree, iq_nj_tree from cogent3 import make_tree from cogent3.core.alignment import Alignment from cogent3.core.tree import PhyloNode from cogent3.evolve.fast_distance import DistanceMatrix from piqtree.exceptions import ParseIqTreeError from piqtree.iqtree._decorator import iqtree_func from piqtree.iqtree._parse_tree_parameters import parse_model_parameters from piqtree.model import Model, make_model from piqtree.util import get_newick, process_rand_seed_nonzero, validate_other_options iq_build_tree = iqtree_func(iq_build_tree, hide_files=True) iq_fit_tree = iqtree_func(iq_fit_tree, hide_files=True) iq_nj_tree = iqtree_func(iq_nj_tree, hide_files=True) iq_consensus_tree = iqtree_func(iq_consensus_tree, hide_files=True) def _rename_iq_tree(tree: PhyloNode, names: Sequence[str]) -> None: for tip in tree.tips(): tip.name = names[int(tip.name)] def _tree_equal(node1: PhyloNode, node2: PhyloNode) -> bool: children_group1 = node1.children children_group2 = node2.children if len(children_group1) != len(children_group2): return False # recursively check if two PhyloNodes have the same name and branch length, and do the same for their children. for child1, child2 in zip(children_group1, children_group2, strict=True): if not _tree_equal(child1, child2): return False # handle empty/different internal node names if children_group1 == []: return node1.name == node2.name and node1.length == node2.length return node1.length == node2.length def _process_tree_yaml( tree_yaml: dict[str, Any], names: Sequence[str], model: Model, ) -> PhyloNode: newick = tree_yaml["PhyloTree"]["newick"] tree = make_tree(newick) candidates = tree_yaml["CandidateSet"] likelihood = None for candidate in candidates.values(): candidate_likelihood, candidate_newick = candidate.split(" ") candidate_tree = make_tree(candidate_newick) if _tree_equal(candidate_tree, tree): likelihood = float(candidate_likelihood) break if likelihood is None: msg = "IQ-TREE output is malformed, likelihood not found." raise ParseIqTreeError(msg) tree.params["lnL"] = likelihood parse_model_parameters(tree, tree_yaml, model) # parse rate model, handling various rate model names if key := next((key for key in tree_yaml if key.startswith("Rate")), None): tree.params[key] = tree_yaml[key] _rename_iq_tree(tree, names) tree.name_unnamed_nodes() tree.params["model"] = str(model) return tree # Bad options INVALID_BUILD_TREE_PARAMS = [ "-s", # aln file "-m", # model selection "-seed", # seed "-bb", # bootstrap replicates "-nt", # threads "-ntmax", # threads ] def build_tree( aln: Alignment, model: Model | str, rand_seed: int | None = None, bootstrap_replicates: int | None = None, num_threads: int | None = None, other_options: str = "", ) -> PhyloNode: """Reconstruct a phylogenetic tree. Given a sequence alignment, uses IQ-TREE to reconstruct a phylogenetic tree. Parameters ---------- aln : Alignment The sequence alignment. model : Model | str The substitution model with base frequencies and rate heterogeneity. rand_seed : int | None, optional The random seed - None means no seed is used, by default None. bootstrap_replicates : int | None, optional The number of bootstrap replicates to perform, by default None. If 0 is provided, then no bootstrapping is performed. At least 1000 is required to perform bootstrapping. num_threads: int | None, optional Number of threads for IQ-TREE to use, by default None (single-threaded). If 0 is specified, IQ-TREE attempts to find the optimal number of threads. other_options: str, optional Additional command line options for IQ-TREE. Returns ------- PhyloNode The IQ-TREE maximum likelihood tree from the given alignment. """ validate_other_options(other_options, INVALID_BUILD_TREE_PARAMS) if isinstance(model, str): model = make_model(model) rand_seed = process_rand_seed_nonzero(rand_seed) if bootstrap_replicates is None: bootstrap_replicates = 0 if num_threads is None: num_threads = 1 names = aln.names seqs = [str(seq) for seq in aln.iter_seqs(names)] yaml_result = yaml.safe_load( iq_build_tree( names, seqs, str(model), rand_seed, bootstrap_replicates, num_threads, other_options, ), ) return _process_tree_yaml(yaml_result, names, model) INVALID_FIT_TREE_PARAMS = [ "-s", # aln file "-t", # tree specification "-te", # tree specification "-m", # model selection "-nt", # threads "-ntmax", # threads "-blfix", # whether to fix current branch lengths ] def fit_tree( aln: Alignment, tree: PhyloNode, model: Model | str, num_threads: int | None = None, other_options: str = "", *, bl_fixed: bool = False, ) -> PhyloNode: """Fit branch lengths and likelihood for a tree. Given a sequence alignment and a fixed topology, uses IQ-TREE to fit branch lengths to the tree. Parameters ---------- aln : Alignment The sequence alignment. tree : PhyloNode The topology to fit branch lengths to. model : Model | str The substitution model with base frequencies and rate heterogeneity. num_threads: int | None, optional Number of threads for IQ-TREE to use, by default None (single-threaded). If 0 is specified, IQ-TREE attempts to find the optimal number of threads. bl_fixed: bool, optional If True, evaluates likelihood using the provided branch lengths on the tree. Branch lengths will be treated as constant in this case, with any unspecified branch lengths still being optimised. Otherwise if False, branch lengths are fitted to the tree whether provided or not. By default False. other_options: str, optional Additional command line options for IQ-TREE. Returns ------- PhyloNode A phylogenetic tree with the same given topology fitted with branch lengths. """ validate_other_options(other_options, INVALID_FIT_TREE_PARAMS) if isinstance(model, str): model = make_model(model) if num_threads is None: num_threads = 1 names = aln.names seqs = [str(seq) for seq in aln.iter_seqs(names)] newick = get_newick(tree) yaml_result = yaml.safe_load( iq_fit_tree( names, seqs, str(model), newick, bl_fixed, 0, num_threads, other_options, ), ) return _process_tree_yaml(yaml_result, names, model) def nj_tree( pairwise_distances: DistanceMatrix, *, allow_negative: bool = False, ) -> PhyloNode: """Construct a neighbour joining tree from a pairwise distance matrix. Parameters ---------- pairwise_distances : DistanceMatrix Pairwise distances to construct neighbour joining tree from. allow_negative : bool, optional Whether to allow negative branch lengths in the output. Coerces to 0 if not allowed, by default False. Returns ------- PhyloNode The neighbour joining tree. See Also -------- jc_distances : construction of pairwise JC distance matrix from alignment. """ if np.isnan(pairwise_distances.array).any(): msg = "The pairwise distance matrix cannot contain NaN values." raise ValueError(msg) newick_tree = iq_nj_tree( pairwise_distances.keys(), np.array(pairwise_distances).flatten(), ) tree = make_tree(newick_tree) if not allow_negative: for node in tree.preorder(include_self=False): node.length = max(cast("float", node.length), 0) return tree def _all_same_taxa_set(trees: Iterable[PhyloNode]) -> bool: tree_it = iter(trees) try: taxa_set = set(next(tree_it).get_tip_names()) except StopIteration: return True return all(taxa_set == set(tree.get_tip_names()) for tree in tree_it) _SUPPORT_AGGREGATES: dict[str, Callable[[Iterable[float]], float]] = { "mean": statistics.mean, "max": max, "min": min, } def _transfer_support( consensus: PhyloNode, trees: Iterable[PhyloNode], aggregate: Callable[[Iterable[float]], float], ) -> None: """Set each consensus clade's support from the input trees' support for the same split.""" taxa = frozenset(consensus.get_tip_names()) reference = min(taxa) def split_key(node: PhyloNode) -> frozenset[str]: side = frozenset(node.get_tip_names()) return taxa - side if reference in side else side lookup: dict[frozenset[str], list[float]] = {} for tree in trees: for node in tree.postorder(): if node.is_tip() or node.is_root(): continue support = getattr(node, "support", None) if support is None: continue lookup.setdefault(split_key(node), []).append(support) for node in consensus.postorder(): if node.is_tip() or node.is_root(): continue values = lookup.get(split_key(node)) if values: node.support = aggregate(values) def consensus_tree( trees: Iterable[PhyloNode], *, min_support: float = 0.5, support_aggregate: str | None = "mean", ) -> PhyloNode: """Build a consensus tree, defaults to majority-rule consensus tree. The min_support parameter represents the proportion of trees a clade must appear in to be in the resulting consensus tree. If min_support is 1.0, computes the strict consensus tree. If min_support is 0.0, computes the extended majority-rule consensus tree. By default the input trees' own support values are transferred onto matching consensus clades. Parameters ---------- trees : Iterable[PhyloNode] The trees to form a consensus tree from. min_support : float, optional The minimum support for a clade to appear in the consensus tree, by default 0.5. support_aggregate : str | None, optional How to combine the input trees' support for a shared clade. One of "mean" (default), "max", "min". If None, the consensus' own clade-frequency support is kept and the input support ignored. Returns ------- PhyloNode The constructed consensus tree. """ if not 0 <= min_support <= 1: msg = f"Only min support values in the range 0 <= value <= 1 are supported, got {min_support}" raise ValueError(msg) if support_aggregate is not None and support_aggregate not in _SUPPORT_AGGREGATES: allowed = ", ".join(sorted(_SUPPORT_AGGREGATES)) msg = f"support_aggregate must be one of {allowed} or None, got {support_aggregate!r}" raise ValueError(msg) trees = list(trees) if not _all_same_taxa_set(trees): msg = "Trees must be on same taxa set." raise ValueError(msg) newick_trees = [get_newick(tree) for tree in trees] consensus = make_tree(iq_consensus_tree(newick_trees, min_support)) if support_aggregate is not None: _transfer_support(consensus, trees, _SUPPORT_AGGREGATES[support_aggregate]) return consensus iqtree-piqtree-b8a3d6a/src/piqtree/model/000077500000000000000000000000001521173175100205075ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/src/piqtree/model/__init__.py000066400000000000000000000017211521173175100226210ustar00rootroot00000000000000"""Models available in IQ-TREE.""" from ._freq_type import CustomBaseFreq, FreqType, get_freq_type from ._model import Model, make_model from ._options import available_freq_type, available_models, available_rate_type from ._rate_type import ( DiscreteGammaModel, FreeRateModel, RateModel, RateType, get_rate_type, ) from ._substitution_model import ( AaModel, LieModel, LieModelInstance, StandardDnaModel, StandardDnaModelInstance, SubstitutionModel, get_substitution_model, ) __all__ = [ "AaModel", "CustomBaseFreq", "DiscreteGammaModel", "FreeRateModel", "FreqType", "LieModel", "LieModelInstance", "Model", "RateModel", "RateType", "StandardDnaModel", "StandardDnaModelInstance", "SubstitutionModel", "available_freq_type", "available_models", "available_rate_type", "get_freq_type", "get_rate_type", "get_substitution_model", "make_model", ] iqtree-piqtree-b8a3d6a/src/piqtree/model/_freq_type.py000066400000000000000000000075521521173175100232270ustar00rootroot00000000000000import contextlib import functools from collections.abc import Sequence from enum import Enum, unique @unique class FreqType(Enum): """Types of base frequencies.""" F = "F" FO = "FO" FQ = "FQ" @staticmethod @functools.cache def _descriptions() -> dict["FreqType", str]: return { FreqType.F: "Empirical state frequency observed from the data.", FreqType.FO: "State frequency optimized by maximum-likelihood from the data. Note that this is with letter-O and not digit-0.", FreqType.FQ: "Equal state frequency.", } @property def description(self) -> str: """The description of the FreqType. Returns ------- str The description of the FreqType. """ return self._descriptions()[self] def iqtree_str(self) -> str: return self.value class CustomBaseFreq: def __init__(self, frequencies: Sequence[float]) -> None: """Create a custom base frequency specification. For DNA models the order of the frequencies is: A C G T For AA models the order of the frequencies is: | A | R | N | D | C | Q | E | G | H | I | L | K | M | F | P | S | T | W | Y | V | |-----|-----|-----|-----|-----|----|----|----|----|----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----| | Ala | Arg | Asn | Asp | Cys | Gln| Glu| Gly| His| Ile| Leu | Lys | Met | Phe | Pro | Ser | Thr | Trp | Tyr | Val | IQ-TREE normalises the frequencies if they do not sum to one. Parameters ---------- frequencies : Sequence[float] The fixed base frequencies. """ self.frequencies = frequencies if len(self.frequencies) not in (4, 20): msg = f"Expected either 4 frequencies for DNA model or 20 for AA model but got {len(self.frequencies)}" raise ValueError(msg) @property def description(self) -> str: return "Fixed base frequencies." def iqtree_str(self) -> str: return f"F{{{','.join(map(str, self.frequencies))}}}" @classmethod def from_str(cls, base_freq_str: str) -> "CustomBaseFreq": if len(base_freq_str) == 0: msg = "An empty string does not specify base frequencies." raise ValueError(msg) if base_freq_str[0] != "F": msg = f"A CustomBaseFreq must start with F but got {base_freq_str!r}." raise ValueError(msg) if base_freq_str[1] != "{" or base_freq_str[-1] != "}": msg = f"A CustomBaseFreq must be parameterised with {{}} but got {base_freq_str!r}." raise ValueError(msg) try: frequencies = tuple( float(val.strip()) for val in base_freq_str[2:-1].split(",") ) except ValueError: msg = f"Unable to parse parameters for CustomBaseFreq: {base_freq_str!r}." raise ValueError(msg) from None return cls(frequencies) def get_freq_type( base_freq_str: str | FreqType | CustomBaseFreq, ) -> FreqType | CustomBaseFreq: """Return the FreqType enum for a given name. Parameters ---------- base_freq_str : str | FreqType | CustomBaseFreq The string form of the frequency type. Returns ------- FreqType | CustomBaseFreq The resolved FreqType Enum or CustomBaseFreq. Raises ------ ValueError If the FreqType name cannot be resolved. """ if isinstance(base_freq_str, (FreqType, CustomBaseFreq)): return base_freq_str shortened = base_freq_str.lstrip("+") with contextlib.suppress(KeyError): return FreqType[shortened] if shortened.startswith("F{"): return CustomBaseFreq.from_str(shortened) msg = f"Unknown state frequency type: {base_freq_str!r}." raise ValueError(msg) iqtree-piqtree-b8a3d6a/src/piqtree/model/_model.py000066400000000000000000000127571521173175100223340ustar00rootroot00000000000000from piqtree.model._freq_type import CustomBaseFreq, FreqType, get_freq_type from piqtree.model._rate_type import RateModel, get_rate_type from piqtree.model._substitution_model import SubstitutionModel, get_substitution_model class Model: """Specification for substitution models. Stores the substitution model with base frequency settings. """ def __init__( self, submod_type: str | SubstitutionModel, freq_type: str | FreqType | CustomBaseFreq | None = None, rate_model: str | RateModel | None = None, *, invariable_sites: bool | float = False, ) -> None: """Construct Model class. Parameters ---------- submod_type : str | SubstitutionModel The substitution model to use. freq_type : str | FreqType | CustomBaseFreq | None, optional State frequency specification, by default None (defaults to empirical base frequencies if not specified by model). rate_model : str | RateModel | None, optional Rate heterogeneity across sites model, by default None (no Gamma and no FreeRate). invariable_sites : bool | float, optional Invariable sites, by default False. If a float in the range [0,1), specifies the proportion of invariable sites. """ self.submod_type = get_substitution_model(submod_type) self.freq_type = get_freq_type(freq_type) if freq_type else None self.rate_type = ( get_rate_type(rate_model, invariable_sites=invariable_sites) if rate_model is not None or invariable_sites else None ) def __hash__(self) -> int: return hash(str(self)) def __repr__(self) -> str: attrs = [ f"submod_type={self.submod_type.iqtree_str()}", f"freq_type={getattr(self.freq_type, 'name', None)}", f"rate_type={getattr(self.rate_type, 'name', None)}", ] return f"Model({', '.join(attrs)})" def __str__(self) -> str: """Convert the model into the IQ-TREE representation. Returns ------- str The IQ-TREE representation of the model. """ iqtree_extra_args = ( x for x in (self.freq_type, self.rate_type) if x is not None ) return "+".join(x.iqtree_str() for x in [self.submod_type, *iqtree_extra_args]) @property def rate_model(self) -> RateModel | None: """The RateModel used, if one is chosen. Returns ------- RateModel | None The RateModel used by the Model. """ return self.rate_type.rate_model if self.rate_type else None @property def invariable_sites(self) -> bool: """Whether invariable sites are used. Returns ------- bool True if invariable sites are used by the model, False otherwise. """ return self.rate_type.invariable_sites if self.rate_type else False @property def proportion_invariable_sites(self) -> float | None: """The proportion of invariable sites if specified. Returns ------- float | None The proportion of invariable sites if specified, None otherwise. """ return self.rate_type.proportion_invariable if self.rate_type else None def make_model(iqtree_str: str) -> Model: """Convert an IQ-TREE model specification into a Model class. Parameters ---------- iqtree_str : str The IQ-TREE model string. Returns ------- Model The equivalent Model class. """ if "+" not in iqtree_str: return Model(iqtree_str) sub_mod_str, components = iqtree_str.split("+", maxsplit=1) freq_type = None invariable_sites: float | bool | None = None rate_model = None for component in components.split("+"): if component.startswith("F"): if freq_type is not None: msg = f"Model {iqtree_str!r} contains multiple base frequency specifications." raise ValueError(msg) freq_type = component elif component.startswith("I"): if invariable_sites is not None: msg = f"Model {iqtree_str!r} contains multiple specifications for invariable sites." raise ValueError(msg) invariable_sites = _parse_invariable_sites(component) elif component.startswith(("G", "R")): if rate_model is not None: msg = f"Model {iqtree_str!r} contains multiple rate heterogeneity specifications." raise ValueError(msg) rate_model = component else: msg = f"Model {iqtree_str!r} contains unexpected component." raise ValueError(msg) if invariable_sites is None: invariable_sites = False return Model(sub_mod_str, freq_type, rate_model, invariable_sites=invariable_sites) def _parse_invariable_sites(component: str) -> bool | float: # Assumes that component starts with "I" remainder = component[1:] if len(remainder) == 0: return True if remainder[0] != "{" or remainder[-1] != "}": msg = f"Invalid specification for proportion of invariable sites, got '{component}'." raise ValueError(msg) number_part = remainder[1:-1] try: return float(number_part) except ValueError: msg = f"Failed to read proportion of invariable sites, got '{component}'" raise ValueError(msg) from None iqtree-piqtree-b8a3d6a/src/piqtree/model/_options.py000066400000000000000000000061261521173175100227200ustar00rootroot00000000000000"""Convenience functions for showing user facing options and their descriptions.""" import functools from typing import Literal from cogent3.core.table import Table, make_table from piqtree.model._freq_type import FreqType from piqtree.model._rate_type import ALL_BASE_RATE_TYPES, get_description from piqtree.model._substitution_model import ( ALL_MODELS_CLASSES, AaModel, LieModel, StandardDnaModel, SubstitutionModel, ) @functools.cache def _make_models( model_classes: type[SubstitutionModel] | tuple[type[SubstitutionModel], ...], ) -> dict[str, list[str]]: data: dict[str, list[str]] = { "Model Type": [], "Abbreviation": [], "Description": [], } if model_classes == SubstitutionModel: model_classes = ALL_MODELS_CLASSES if isinstance(model_classes, type) and issubclass(model_classes, SubstitutionModel): model_classes = (model_classes,) for model_class in model_classes: for model in model_class.iter_available_models(): data["Model Type"].append(model.model_type()) data["Abbreviation"].append(model.iqtree_str()) data["Description"].append(model.description) return data def available_models( model_type: Literal["dna", "protein"] | None = None, *, show_all: bool = True, ) -> Table: """Return a table showing available substitution models. Parameters ---------- model_type : Literal["dna", "protein"] | None, optional The models to fetch, by default None (all models). show_all : bool, optional If True, the representation of the table shows all records, by default True. Returns ------- Table Table with all available models. """ template = "Available {}substitution models" if model_type == "dna": table = make_table( data=_make_models((StandardDnaModel, LieModel)), title=template.format("nucleotide "), ) elif model_type == "protein": table = make_table( data=_make_models(AaModel), title=template.format("protein "), ) else: table = make_table( data=_make_models(SubstitutionModel), title=template.format(""), ) if show_all: table.set_repr_policy(head=table.shape[0]) return table def available_freq_type() -> Table: """Return a table showing available freq type options.""" data: dict[str, list[str]] = {"Freq Type": [], "Description": []} for freq_type in FreqType: data["Freq Type"].append(freq_type.value) data["Description"].append(freq_type.description) return make_table(data=data, title="Available frequency types") def available_rate_type() -> Table: """Return a table showing available rate type options.""" data: dict[str, list[str]] = {"Rate Type": [], "Description": []} for rate_type in ALL_BASE_RATE_TYPES: data["Rate Type"].append(rate_type.iqtree_str()) data["Description"].append(get_description(rate_type)) return make_table(data=data, title="Available rate heterogeneity types") iqtree-piqtree-b8a3d6a/src/piqtree/model/_rate_type.py000066400000000000000000000275611521173175100232270ustar00rootroot00000000000000import itertools from abc import ABC, abstractmethod from collections.abc import Sequence class RateModel(ABC): """Base class for rate models.""" @abstractmethod def iqtree_str(self) -> str: """Convert to an iqtree settings string. Returns ------- str String parsable by IQ-TREE for the rate heterogeneity model. """ class RateType: def __init__( self, *, invariable_sites: bool | float = False, rate_model: RateModel | None = None, ) -> None: """Rate heterogeneity across sites model. Parameters ---------- invariable_sites : bool | float, optional Invariable sites, by default False. If a float in the range [0,1), specifies the proportion of invariable sites. rate_model : RateModel | None, optional Discrete Gamma Model or FreeRate Model, by default None. """ if not isinstance(invariable_sites, bool): if not (0 <= invariable_sites < 1): msg = "The proportion of invariant sites must be in the range [0,1)" raise ValueError(msg) self.invariable_sites = True self.proportion_invariable: float | None = invariable_sites else: self.invariable_sites = invariable_sites self.proportion_invariable = None self.rate_model = rate_model def iqtree_str(self) -> str: """Convert to an iqtree settings string. Returns ------- str String parsable by IQ-TREE for the rate heterogeneity model. """ rate_type_str = "I" if self.invariable_sites else "" if self.proportion_invariable is not None: rate_type_str += f"{{{self.proportion_invariable}}}" if self.rate_model is None: return rate_type_str # Invariant sites and model need to be joined by a '+' if self.invariable_sites: rate_type_str += "+" return rate_type_str + self.rate_model.iqtree_str() @property def name(self) -> str: return self.iqtree_str() class DiscreteGammaModel(RateModel): def __init__( self, rate_categories: int | None = None, alpha: float | None = None, ) -> None: """Discrete Gamma Model. Parameters ---------- rate_categories : int | None, optional The number of rate categories, by default None (uses 4). alpha : float | None, optional The Gamma shape parameter - fixed if not None, by default None References ---------- .. [1] Yang, Ziheng. "Maximum likelihood phylogenetic estimation from DNA sequences with variable rates over sites: approximate methods." Journal of Molecular evolution 39 (1994): 306-314. """ self.rate_categories = rate_categories self.alpha = alpha def iqtree_str(self) -> str: out_str = "G" if self.rate_categories is not None: out_str += str(self.rate_categories) if self.alpha is not None: out_str += f"{{{self.alpha}}}" return out_str @classmethod def from_str(cls, rate_model_str: str) -> "DiscreteGammaModel": if len(rate_model_str) == 0: msg = "An empty string is not a DiscreteGammaModel." raise ValueError(msg) if rate_model_str[0] != "G": msg = f"A DiscreteGammaModel must start with G but got {rate_model_str!r}." raise ValueError(msg) if len(rate_model_str) == 1: return cls() rate_categories = _parse_rate_categories(rate_model_str) parameter_start = rate_model_str.find("{") # If there is no parameterisation if parameter_start == -1: return cls(rate_categories=rate_categories) if not rate_model_str.endswith("}"): msg = f"Missing end bracket for parameterisation {rate_model_str!r}" raise ValueError(msg) try: alpha = float(rate_model_str[parameter_start + 1 : -1]) except ValueError: msg = f"Parameterisation of Discrete Gamma Model is not a number {rate_model_str!r}" raise ValueError(msg) from None return cls(rate_categories=rate_categories, alpha=alpha) class FreeRateModel(RateModel): default_rate_categories = 4 def __init__( self, rate_categories: int | None = None, weights: Sequence[float] | None = None, rates: Sequence[float] | None = None, ) -> None: """FreeRate Model. Parameters ---------- rate_categories : int | None, optional The number of rate categories, by default None (uses 4). weights : Sequence[float] | None, optional The weights for each rate category, by default None rates : Sequence[float] | None, optional The rates for each rate category, by default None References ---------- .. [1] Yang, Ziheng. "A space-time process model for the evolution of DNA sequences." Genetics 139.2 (1995): 993-1005. .. [2] Soubrier, Julien, et al. "The influence of rate heterogeneity among sites on the time dependence of molecular rates." Molecular biology and evolution 29.11 (2012): 3345-3358. """ self.rate_categories = rate_categories if (weights is None) ^ (rates is None): msg = "Must specify both rates and weights or neither." raise ValueError(msg) check_rate_categories = ( rate_categories if rate_categories is not None else FreeRateModel.default_rate_categories ) if weights is None or rates is None: self.weights = None self.rates = None else: if ( len(weights) != check_rate_categories or len(rates) != check_rate_categories ): msg = f"Expected {check_rate_categories} rates and weights but got {len(weights)} and {len(rates)} respectively." raise ValueError(msg) self.weights = list(weights) self.rates = list(rates) def iqtree_str(self) -> str: base = "R" if self.rate_categories is None else f"R{self.rate_categories}" if self.weights is None or self.rates is None: return base weights_and_rates = itertools.chain.from_iterable( zip(self.weights, self.rates, strict=True), ) return f"{base}{{{','.join(str(val) for val in weights_and_rates)}}}" @classmethod def from_str(cls, rate_model_str: str) -> "FreeRateModel": if len(rate_model_str) == 0: msg = "An empty string is not a FreeRateModel." raise ValueError(msg) if rate_model_str[0] != "R": msg = f"A FreeRateModel must start with R but got {rate_model_str!r}." raise ValueError(msg) if len(rate_model_str) == 1: return cls() rate_categories = _parse_rate_categories(rate_model_str) parameter_start = rate_model_str.find("{") # If there is no parameterisation if parameter_start == -1: return cls(rate_categories=rate_categories) if not rate_model_str.endswith("}"): msg = f"Missing end bracket for parameterisation {rate_model_str!r}" raise ValueError(msg) try: weights_and_rates = [ float(part.strip()) for part in rate_model_str[parameter_start + 1 : -1].split(",") ] except ValueError: msg = f"Unable to parse parameters for FreeRateModel: {rate_model_str!r}." raise ValueError(msg) from None expected_params = 2 * ( cls.default_rate_categories if rate_categories is None else rate_categories ) if len(weights_and_rates) != expected_params: msg = f"Expected {expected_params} parameters but got {len(weights_and_rates)}." raise ValueError(msg) weights = weights_and_rates[::2] rates = weights_and_rates[1::2] return cls(rate_categories=rate_categories, weights=weights, rates=rates) ALL_BASE_RATE_TYPES = [ RateType(), RateType(invariable_sites=True), RateType(rate_model=DiscreteGammaModel()), RateType(invariable_sites=True, rate_model=DiscreteGammaModel()), RateType(rate_model=FreeRateModel()), RateType(invariable_sites=True, rate_model=FreeRateModel()), ] _BASE_RATE_TYPE_DESCRIPTIONS = { RateType().iqtree_str(): "no invariable sites, no rate heterogeneity model.", RateType( invariable_sites=True, ).iqtree_str(): "allowing for a proportion of invariable sites.", RateType( rate_model=DiscreteGammaModel(), ).iqtree_str(): "discrete Gamma model (Yang, 1994) with default 4 rate categories. The number of categories can be changed with e.g. +G8.", RateType( invariable_sites=True, rate_model=DiscreteGammaModel(), ).iqtree_str(): "invariable site plus discrete Gamma model (Gu et al., 1995).", RateType( rate_model=FreeRateModel(), ).iqtree_str(): "FreeRate model (Yang, 1995; Soubrier et al., 2012) that generalizes the +G model by relaxing the assumption of Gamma-distributed rates. The number of categories can be specified with e.g. +R6 (default 4 categories if not specified). The FreeRate model typically fits data better than the +G model and is recommended for analysis of large data sets.", RateType( invariable_sites=True, rate_model=FreeRateModel(), ).iqtree_str(): "invariable site plus FreeRate model.", } def get_description(rate_type: RateType) -> str: rate_type_str = "".join(c for c in rate_type.iqtree_str() if not c.isdigit()) return _BASE_RATE_TYPE_DESCRIPTIONS[rate_type_str] def get_rate_type( rate_model: str | RateModel | None = None, *, invariable_sites: bool | float = False, ) -> RateType: """Make a RateType from a chosen rate model and invariable sites. Parameters ---------- rate_model : str | RateModel | None, optional The chosen rate model, by default None. invariable_sites : bool | float, optional Invariable sites, by default False. If a float in the range [0,1), specifies the proportion of invariable sites. Returns ------- RateType RateType generated from the rate model with invariable sites. """ if isinstance(rate_model, RateModel): return RateType(rate_model=rate_model, invariable_sites=invariable_sites) if rate_model is None: return RateType(invariable_sites=invariable_sites) if not isinstance(rate_model, str): msg = f"Unexpected type for rate_model: {type(rate_model)}" raise TypeError(msg) stripped_rate_model = rate_model.lstrip("+") rate_model_char = stripped_rate_model[0] if rate_model_char == "G": rate_model = DiscreteGammaModel.from_str(stripped_rate_model) elif rate_model_char == "R": rate_model = FreeRateModel.from_str(stripped_rate_model) else: msg = f"Unexpected value for rate_model {rate_model!r}" raise ValueError(msg) return RateType( rate_model=rate_model, invariable_sites=invariable_sites, ) def _parse_rate_categories(rate_model_str: str) -> int | None: # Assume that the rate model str starts with a G or an R parameters_start = rate_model_str.find("{") # There is no {} style parameterisation if parameters_start == -1: categories_str = rate_model_str[1:] else: categories_str = rate_model_str[1:parameters_start] if len(categories_str) == 0: return None try: return int(categories_str) except ValueError: msg = f"Invalid specification for rate categories {rate_model_str!r}" raise ValueError(msg) from None iqtree-piqtree-b8a3d6a/src/piqtree/model/_substitution_model.py000066400000000000000000000545471521173175100251730ustar00rootroot00000000000000import contextlib import functools from collections.abc import Sequence from dataclasses import dataclass from enum import Enum, unique from typing import ClassVar, Literal, cast class SubstitutionModel: """Base class for substitution models.""" @staticmethod def model_type() -> str: """Get the type of the model. Returns ------- str The type of the model. """ raise NotImplementedError def iqtree_str(self) -> str: """Get the IQ-TREE representation of the model. Returns ------- str The IQ-TREE representation of the model. """ raise NotImplementedError def get_moltype(self) -> Literal["dna", "protein"]: """The model's moltype string for cogent3 Returns ------- str The model's moltype string. """ raise NotImplementedError @property def base_model(self) -> "SubstitutionModel": """Get the base model enum used by the model. Returns ------- SubstitutionModel The enum of the model. """ raise NotImplementedError @staticmethod def iter_available_models() -> Sequence["SubstitutionModel"]: """Get the available models for the model type. Returns ------- Sequence[SubstitutionModel] The available models. """ raise NotImplementedError @staticmethod def num_available_models() -> int: """Get the number of available models for the model type. Returns ------- int The number of available models. """ raise NotImplementedError @property def description(self) -> str: """The model's description. Returns ------- str The model's description. """ raise NotImplementedError @dataclass(frozen=True) class StandardDnaModelInstance(SubstitutionModel): dna_model: "StandardDnaModel" model_params: Sequence[float] | None = None @staticmethod def model_type() -> str: return "nucleotide" def iqtree_str(self) -> str: params = ( f"{{{','.join(map(str, self.model_params))}}}" if self.model_params else "" ) return f"{self.dna_model.value}{params}" def get_moltype(self) -> Literal["dna", "protein"]: return "dna" @property def base_model(self) -> "StandardDnaModel": return self.dna_model @staticmethod def iter_available_models() -> Sequence["StandardDnaModel"]: return StandardDnaModel.iter_available_models() @staticmethod def num_available_models() -> int: return StandardDnaModel.num_available_models() @property def description(self) -> str: return StandardDnaModel._descriptions()[self.dna_model] # noqa: SLF001 @unique class StandardDnaModel(SubstitutionModel, Enum): """Standard DNA substitution models.""" JC = "JC" JC69 = "JC69" F81 = "F81" K80 = "K80" K2P = "K2P" HKY = "HKY" HKY85 = "HKY85" TN = "TN" TN93 = "TN93" TNe = "TNe" K81 = "K81" K3P = "K3P" K81u = "K81u" TPM2 = "TPM2" TPM2u = "TPM2u" TPM3 = "TPM3" TPM3u = "TPM3u" TIM = "TIM" TIMe = "TIMe" TIM2 = "TIM2" TIM2e = "TIM2e" TIM3 = "TIM3" TIM3e = "TIM3e" TVM = "TVM" TVMe = "TVMe" SYM = "SYM" GTR = "GTR" STRSYM = "STRSYM" UNREST = "UNREST" def __call__( self, model_params: Sequence[float] | None = None, ) -> StandardDnaModelInstance: """Parameterise the model. If parameters are not supplied, the model is not parameterised. Parameters ---------- model_params : Sequence[float] | None, optional The relative substitution rates, by default None Returns ------- StandardDnaModelInstance The parameterised model. """ return StandardDnaModelInstance(self, model_params) @staticmethod def model_type() -> str: return "nucleotide" def iqtree_str(self) -> str: return self.value def get_moltype(self) -> Literal["dna", "protein"]: return "dna" @property def base_model(self) -> "StandardDnaModel": return self @staticmethod def iter_available_models() -> Sequence["StandardDnaModel"]: return list(StandardDnaModel) @staticmethod def num_available_models() -> int: return len(StandardDnaModel) @property def description(self) -> str: return self._descriptions()[self] @staticmethod @functools.cache def _descriptions() -> dict[SubstitutionModel, str]: return { StandardDnaModel.JC: "Equal substitution rates and equal base frequencies (Jukes and Cantor, 1969).", StandardDnaModel.JC69: "Equal substitution rates and equal base frequencies (Jukes and Cantor, 1969).", StandardDnaModel.F81: "Equal rates but unequal base freq. (Felsenstein, 1981).", StandardDnaModel.K80: "Unequal transition/transversion rates and equal base freq. (Kimura, 1980).", StandardDnaModel.K2P: "Unequal transition/transversion rates and equal base freq. (Kimura, 1980).", StandardDnaModel.HKY: "Unequal transition/transversion rates and unequal base freq. (Hasegawa, Kishino and Yano, 1985).", StandardDnaModel.HKY85: "Unequal transition/transversion rates and unequal base freq. (Hasegawa, Kishino and Yano, 1985).", StandardDnaModel.TN: "Like HKY but unequal purine/pyrimidine rates (Tamura and Nei, 1993).", StandardDnaModel.TN93: "Like HKY but unequal purine/pyrimidine rates (Tamura and Nei, 1993).", StandardDnaModel.TNe: "Like TN but equal base freq.", StandardDnaModel.K81: "Three substitution types model and equal base freq. (Kimura, 1981).", StandardDnaModel.K3P: "Three substitution types model and equal base freq. (Kimura, 1981).", StandardDnaModel.K81u: "Like K81 but unequal base freq.", StandardDnaModel.TPM2: "AC=AT, AG=CT, CG=GT and equal base freq.", StandardDnaModel.TPM2u: "Like TPM2 but unequal base freq.", StandardDnaModel.TPM3: "AC=CG, AG=CT, AT=GT and equal base freq.", StandardDnaModel.TPM3u: "Like TPM3 but unequal base freq.", StandardDnaModel.TIM: "Transition model, AC=GT, AT=CG and unequal base freq.", StandardDnaModel.TIMe: "Like TIM but equal base freq.", StandardDnaModel.TIM2: "AC=AT, CG=GT and unequal base freq.", StandardDnaModel.TIM2e: "Like TIM2 but equal base freq.", StandardDnaModel.TIM3: "AC=CG, AT=GT and unequal base freq.", StandardDnaModel.TIM3e: "Like TIM3 but equal base freq.", StandardDnaModel.TVM: "Transversion model, AG=CT and unequal base freq.", StandardDnaModel.TVMe: "Like TVM but equal base freq.", StandardDnaModel.SYM: "Symmetric model with unequal rates but equal base freq. (Zharkikh, 1994).", StandardDnaModel.GTR: "General time reversible model with unequal rates and unequal base freq. (Tavare, 1986).", StandardDnaModel.STRSYM: "Strand-symmetric model (Bielawski and Gold, 2002).", StandardDnaModel.UNREST: "Unrestricted model.", } lie_model_pairing = Literal["RY", "WS", "MK"] @dataclass(frozen=True) class LieModelInstance(SubstitutionModel): lie_model: "LieModel" pairing: lie_model_pairing | None = None model_params: Sequence[float] | None = None valid_pairings: ClassVar[ tuple[lie_model_pairing, lie_model_pairing, lie_model_pairing] ] = "RY", "WS", "MK" pairing_descriptions: ClassVar[dict[lie_model_pairing, str]] = { "RY": "purine-pyrimidine pairing (default).", "WS": "weak-strong pairing.", "MK": "aMino-Keto pairing", } def __post_init__(self) -> None: if ( self.pairing is not None and self.pairing not in LieModelInstance.valid_pairings ): msg = f"Invalid Lie Model pairing prefix: '{self.pairing}'" raise ValueError(msg) @staticmethod def model_type() -> str: return "nucleotide" def iqtree_str(self) -> str: prefix = self.pairing or "" params = ( f"{{{','.join(map(str, self.model_params))}}}" if self.model_params else "" ) return f"{prefix}{self.lie_model.value}{params}" def get_moltype(self) -> Literal["dna", "protein"]: return "dna" @property def base_model(self) -> "LieModel": return self.lie_model @staticmethod def iter_available_models() -> Sequence["LieModelInstance"]: return [ LieModelInstance(lie_model, prefix) for prefix in (None, *LieModelInstance.valid_pairings) for lie_model in LieModel ] @staticmethod def num_available_models() -> int: return (len(LieModelInstance.valid_pairings) + 1) * len(LieModel) @property def description(self) -> str: base_desc = LieModel._descriptions()[self.lie_model] # noqa: SLF001 if self.pairing is None: return base_desc return f"{base_desc} Pairing: {LieModelInstance.pairing_descriptions[self.pairing]}" class LieModel(SubstitutionModel, Enum): LIE_1_1 = "1.1" LIE_2_2b = "2.2b" LIE_3_3a = "3.3a" LIE_3_3b = "3.3b" LIE_3_3c = "3.3c" LIE_3_4 = "3.4" LIE_4_4a = "4.4a" LIE_4_4b = "4.4b" LIE_4_5a = "4.5a" LIE_4_5b = "4.5b" LIE_5_6a = "5.6a" LIE_5_6b = "5.6b" LIE_5_7a = "5.7a" LIE_5_7b = "5.7b" LIE_5_7c = "5.7c" LIE_5_11a = "5.11a" LIE_5_11b = "5.11b" LIE_5_11c = "5.11c" LIE_5_16 = "5.16" LIE_6_6 = "6.6" LIE_6_7a = "6.7a" LIE_6_7b = "6.7b" LIE_6_8a = "6.8a" LIE_6_8b = "6.8b" LIE_6_17a = "6.17a" LIE_6_17b = "6.17b" LIE_8_8 = "8.8" LIE_8_10a = "8.10a" LIE_8_10b = "8.10b" LIE_8_16 = "8.16" LIE_8_17 = "8.17" LIE_8_18 = "8.18" LIE_9_20a = "9.20a" LIE_9_20b = "9.20b" LIE_10_12 = "10.12" LIE_10_34 = "10.34" LIE_12_12 = "12.12" def __call__( self, pairing: lie_model_pairing | None = None, model_params: Sequence[float] | None = None, ) -> LieModelInstance: """Parameterise the model. If parameters are not supplied, the model is not parameterised. Parameters ---------- pairing : Literal["RY", "WS", "MK"] | None, optional The pairing type. RY: purine-pyrimidine pairing WS: weak-strong pairing MK: aMino-Keto pairing by default None (unparameterised uses RY). model_params : Sequence[float] | None, optional The weights of the basis matrices, the weights should be bounded between -0.98 and 0.98 exclusive, by default None. Returns ------- LieModelInstance The parameterised Lie Markov Model. """ return LieModelInstance(self, pairing, model_params) @staticmethod def model_type() -> str: return "nucleotide" def iqtree_str(self) -> str: return self.value def get_moltype(self) -> Literal["dna", "protein"]: return "dna" @property def base_model(self) -> "LieModel": return self @staticmethod def iter_available_models() -> Sequence[LieModelInstance]: return LieModelInstance.iter_available_models() @staticmethod def num_available_models() -> int: return LieModelInstance.num_available_models() @property def description(self) -> str: return LieModel._descriptions()[self] @staticmethod @functools.cache def _descriptions() -> dict[SubstitutionModel, str]: return { LieModel.LIE_1_1: "Reversible model. Equal base frequencies. equiv. to JC", LieModel.LIE_2_2b: "Reversible model. Equal base frequencies. equiv. to K2P", LieModel.LIE_3_3a: "Reversible model. Equal base frequencies. equiv. to K3P", LieModel.LIE_3_3b: "Non-reversible model. Equal base frequencies.", LieModel.LIE_3_3c: "Reversible model. Equal base frequencies. equiv. to TNe", LieModel.LIE_3_4: "Reversible model. f(A)=f(G) and f(C)=f(T).", LieModel.LIE_4_4a: "Reversible model. Unconstrained base frequencies. equiv. to F81", LieModel.LIE_4_4b: "Reversible model. f(A)=f(G) and f(C)=f(T).", LieModel.LIE_4_5a: "Non-reversible model. f(A)=f(G) and f(C)=f(T).", LieModel.LIE_4_5b: "Non-reversible model. f(A)=f(G) and f(C)=f(T).", LieModel.LIE_5_6a: "Non-reversible model. Equal base frequencies.", LieModel.LIE_5_6b: "Non-reversible model. Unconstrained base frequencies.", LieModel.LIE_5_7a: "Non-reversible model. f(A)+f(G)=0.5=f(C)+f(T).", LieModel.LIE_5_7b: "Non-reversible model. Equal base frequencies.", LieModel.LIE_5_7c: "Non-reversible model. Equal base frequencies.", LieModel.LIE_5_11a: "Non-reversible model. f(A)+f(G)=0.5=f(C)+f(T).", LieModel.LIE_5_11b: "Non-reversible model. Equal base frequencies.", LieModel.LIE_5_11c: "Non-reversible model. Equal base frequencies.", LieModel.LIE_5_16: "Non-reversible model. f(A)=f(G) and f(C)=f(T).", LieModel.LIE_6_6: "Non-reversible model. f(A)=f(G) and f(C)=f(T). equiv. to STRSYM for strand-symmetric model (Bielawski and Gold, 2002)", LieModel.LIE_6_7a: "Non-reversible model. Unconstrained base frequencies. F81+K3P", LieModel.LIE_6_7b: "Non-reversible model. Unconstrained base frequencies.", LieModel.LIE_6_8a: "Non-reversible model. Unconstrained base frequencies.", LieModel.LIE_6_8b: "Non-reversible model. f(A)=f(G) and f(C)=f(T).", LieModel.LIE_6_17a: "Non-reversible model. f(A)=f(G) and f(C)=f(T).", LieModel.LIE_6_17b: "Non-reversible model. f(A)=f(G) and f(C)=f(T).", LieModel.LIE_8_8: "Non-reversible model. Unconstrained base frequencies.", LieModel.LIE_8_10a: "Non-reversible model. Unconstrained base frequencies.", LieModel.LIE_8_10b: "Non-reversible model. f(A)=f(G) and f(C)=f(T).", LieModel.LIE_8_16: "Non-reversible model. Unconstrained base frequencies.", LieModel.LIE_8_17: "Non-reversible model. Unconstrained base frequencies.", LieModel.LIE_8_18: "Non-reversible model. Unconstrained base frequencies.", LieModel.LIE_9_20a: "Non-reversible model. f(A)+f(G)=0.5=f(C)+f(T).", LieModel.LIE_9_20b: "Non-reversible model. Equal base frequencies. Doubly stochastic", LieModel.LIE_10_12: "Non-reversible model. Unconstrained base frequencies.", LieModel.LIE_10_34: "Non-reversible model. Unconstrained base frequencies.", LieModel.LIE_12_12: "Non-reversible model. Unconstrained base frequencies. equiv. to UNREST (unrestricted model)", } @unique class AaModel(SubstitutionModel, Enum): """Protein substitution models.""" Blosum62 = "Blosum62" cpREV = "cpREV" Dayhoff = "Dayhoff" DCMut = "DCMut" EAL = "EAL" ELM = "ELM" FLAVI = "FLAVI" FLU = "FLU" GTR20 = "GTR20" HIVb = "HIVb" HIVw = "HIVw" JTT = "JTT" JTTDCMut = "JTTDCMut" LG = "LG" mtART = "mtART" mtMAM = "mtMAM" mtREV = "mtREV" mtZOA = "mtZOA" mtMet = "mtMet" mtVer = "mtVer" mtInv = "mtInv" NQ_bird = "NQ.bird" NQ_insect = "NQ.insect" NQ_mammal = "NQ.mammal" NQ_pfam = "NQ.pfam" NQ_plant = "NQ.plant" NQ_yeast = "NQ.yeast" Poisson = "Poisson" PMB = "PMB" Q_bird = "Q.bird" Q_insect = "Q.insect" Q_mammal = "Q.mammal" Q_pfam = "Q.pfam" Q_plant = "Q.plant" Q_yeast = "Q.yeast" rtREV = "rtREV" VT = "VT" WAG = "WAG" @staticmethod def model_type() -> str: return "protein" def iqtree_str(self) -> str: return self.value def get_moltype(self) -> Literal["dna", "protein"]: return "protein" @property def base_model(self) -> "AaModel": return self @staticmethod def iter_available_models() -> Sequence["AaModel"]: return list(AaModel) @staticmethod def num_available_models() -> int: return len(AaModel) @property def description(self) -> str: return self._descriptions()[self] @staticmethod @functools.cache def _descriptions() -> dict[SubstitutionModel, str]: return { AaModel.Blosum62: "BLOcks SUbstitution Matrix (Henikoff and Henikoff, 1992). Note that BLOSUM62 is not recommended for phylogenetic analysis as it was designed mainly for sequence alignments.", AaModel.cpREV: "chloroplast matrix (Adachi et al., 2000).", AaModel.Dayhoff: "General matrix (Dayhoff et al., 1978).", AaModel.DCMut: "Revised Dayhoff matrix (Kosiol and Goldman, 2005).", AaModel.EAL: "General matrix. To be used with profile mixture models (for eg. EAL+C60) for reconstructing relationships between eukaryotes and Archaea (Banos et al., 2024).", AaModel.ELM: "General matrix. To be used with profile mixture models (for eg. ELM+C60) for phylogenetic analysis of proteins encoded by nuclear genomes of eukaryotes (Banos et al., 2024).", AaModel.FLAVI: "Flavivirus (Le and Vinh, 2020).", AaModel.FLU: "Influenza virus (Dang et al., 2010).", AaModel.GTR20: "General time reversible models with 190 rate parameters.", AaModel.HIVb: "HIV between-patient matrix HIV-Bm (Nickle et al., 2007).", AaModel.HIVw: "HIV within-patient matrix HIV-Wm (Nickle et al., 2007).", AaModel.JTT: "General matrix (Jones et al., 1992).", AaModel.JTTDCMut: "Revised JTT matrix (Kosiol and Goldman, 2005).", AaModel.LG: "General matrix (Le and Gascuel, 2008).", AaModel.mtART: "Mitochondrial Arthropoda (Abascal et al., 2007).", AaModel.mtMAM: "Mitochondrial Mammalia (Yang et al., 1998).", AaModel.mtREV: "Mitochondrial Vertebrate (Adachi and Hasegawa, 1996).", AaModel.mtZOA: "Mitochondrial Metazoa (Animals) (Rota-Stabelli et al., 2009).", AaModel.mtMet: "Mitochondrial Metazoa (Vinh et al., 2017).", AaModel.mtVer: "Mitochondrial Vertebrate (Vinh et al., 2017).", AaModel.mtInv: "Mitochondrial Invertebrate (Vinh et al., 2017).", AaModel.NQ_bird: "Non-reversible Q matrix (Dang et al., 2022) estimated for birds (Jarvis et al., 2015).", AaModel.NQ_insect: "Non-reversible Q matrix (Dang et al., 2022) estimated for insects (Misof et al., 2014).", AaModel.NQ_mammal: "Non-reversible Q matrix (Dang et al., 2022) estimated for mammals (Wu et al., 2018).", AaModel.NQ_pfam: "General non-reversible Q matrix (Dang et al., 2022) estimated from Pfam version 31 database (El-Gebali et al., 2018).", AaModel.NQ_plant: "Non-reversible Q matrix (Dang et al., 2022) estimated for plants (Ran et al., 2018).", AaModel.NQ_yeast: "Non-reversible Q matrix (Dang et al., 2022) estimated for yeasts (Shen et al., 2018).", AaModel.Poisson: "Equal amino-acid exchange rates and frequencies.", AaModel.PMB: "Probability Matrix from Blocks, revised BLOSUM matrix (Veerassamy et al., 2004).", AaModel.Q_bird: "Q matrix (Minh et al., 2021) estimated for birds (Jarvis et al., 2015).", AaModel.Q_insect: "Q matrix (Minh et al., 2021) estimated for insects (Misof et al., 2014).", AaModel.Q_mammal: "Q matrix (Minh et al., 2021) estimated for mammals (Wu et al., 2018).", AaModel.Q_pfam: "General Q matrix (Minh et al., 2021) estimated from Pfam version 31 database (El-Gebali et al., 2018).", AaModel.Q_plant: "Q matrix (Minh et al., 2021) estimated for plants (Ran et al., 2018).", AaModel.Q_yeast: "Q matrix (Minh et al., 2021) estimated for yeasts (Shen et al., 2018).", AaModel.rtREV: "Retrovirus (Dimmic et al., 2002).", AaModel.VT: "General 'Variable Time' matrix (Mueller and Vingron, 2000).", AaModel.WAG: "General matrix (Whelan and Goldman, 2001).", } ALL_MODELS_CLASSES: tuple[type[SubstitutionModel], ...] = ( StandardDnaModel, LieModelInstance, AaModel, ) def get_substitution_model(name: str | SubstitutionModel) -> SubstitutionModel: """Return the substitution model enum for a given name. Parameters ---------- name : str | SubstitutionModel The name of the chosen substitution model. Returns ------- SubstitutionModel The corresponding substitution model enum. """ if isinstance(name, SubstitutionModel): return name norm_name = _normalise_prefix(name) if len(norm_name) == 0: msg = f"Unknown substitution model: {name!r}" raise ValueError(msg) # No parameterisation of AaModels with contextlib.suppress(KeyError): return AaModel[norm_name] model_params = _get_model_parameters(norm_name) if model_params is not None: norm_name = norm_name[: norm_name.find("{")] with contextlib.suppress(KeyError): return StandardDnaModel[norm_name](model_params) # Lie models prefix = _get_lie_prefix(norm_name) if prefix is not None: norm_name = norm_name[2:] with contextlib.suppress(KeyError): return LieModel["LIE_" + norm_name](prefix, model_params) msg = f"Unknown substitution model: {name!r}" raise ValueError(msg) def _normalise_prefix(name: str) -> str: parts = name.split("{") parts[0] = parts[0].replace(".", "_") return "{".join(parts) def _get_lie_prefix(name: str) -> lie_model_pairing | None: potential_prefix = name[:2] if potential_prefix in LieModelInstance.valid_pairings: return cast("lie_model_pairing", potential_prefix) return None def _get_model_parameters(name: str) -> tuple[float, ...] | None: params_start = name.find("{") if params_start == -1: # No params return None # The model is parameterised here if name[-1] != "}": msg = f"Missing closing bracket for parameterisation of {name!r}" raise ValueError(msg) return tuple( float(param.strip()) for param in name[params_start + 1 : -1].split(",") ) iqtree-piqtree-b8a3d6a/src/piqtree/py.typed000066400000000000000000000000001521173175100210740ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/src/piqtree/util/000077500000000000000000000000001521173175100203645ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/src/piqtree/util/__init__.py000066400000000000000000000040171521173175100224770ustar00rootroot00000000000000import secrets from collections.abc import Iterable from cogent3.core.tree import PhyloNode def validate_other_options(other_options: str, banned_options: Iterable[str]) -> None: option_parts = set(other_options.split()) for banned_option in banned_options: if banned_option in option_parts: msg = f"Option {banned_option!r} will be overridden by parameter of function. Use the parameter directly instead." raise ValueError(msg) def get_newick(tree: PhyloNode) -> str: return tree.get_newick(with_distances=True, escape_name=False) def make_rand_seed() -> int: """Make a 32-bit random seed. Returns ------- int A 32-bit random seed. """ seed = secrets.randbits(32) return seed if seed < (1 << 31) else seed - (1 << 32) def make_nonzero_rand_seed() -> int: """Make a non-zero 32-bit random seed. Returns ------- int A non-zero 32-bit random seed. """ while (seed := make_rand_seed()) == 0: pass # pragma: no cover return seed def process_rand_seed_nonzero(seed: int | None) -> int: """Process a random seed before sending to IQ-TREE. Some functions treat 0 as non-deterministic. For consistency between methods, 0 is treated as always deterministic and replaced with a pre-determined number. If the seed is None, a random seed is generated. If the seed is 0, it is replaced with a pre-determined number (1074213633). If the seed is anything else, returns that number. Parameters ---------- seed : int | None The random seed to process. Returns ------- int The original seed if no processing is required. Otherwise if the original seed was None, a random non-zero seed is returned. If the original seed was zero, a pre-determined number is returned. """ if seed == 0: seed = 1074213633 # Randomly chosen once with make_rand_seed if seed is None: seed = make_nonzero_rand_seed() return seed iqtree-piqtree-b8a3d6a/tests/000077500000000000000000000000001521173175100163115ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/tests/conftest.py000066400000000000000000000042151521173175100205120ustar00rootroot00000000000000import pathlib import pytest from cogent3 import PhyloNode, load_aligned_seqs, make_tree from cogent3.core.alignment import Alignment @pytest.fixture(scope="session") def DATA_DIR() -> pathlib.Path: return pathlib.Path(__file__).parent / "data" @pytest.fixture def three_otu(DATA_DIR: pathlib.Path) -> Alignment: aln = load_aligned_seqs(DATA_DIR / "example.fasta", moltype="dna") aln = aln.take_seqs(["Human", "Rhesus", "Mouse"]) return aln.omit_gap_pos(allowed_gap_frac=0) @pytest.fixture def four_otu(DATA_DIR: pathlib.Path) -> Alignment: aln = load_aligned_seqs( DATA_DIR / "example.fasta", moltype="dna", ) aln = aln.take_seqs(["Human", "Chimpanzee", "HumpbackW", "SpermWhale"]) aln = aln.omit_gap_pos(allowed_gap_frac=0) return aln[::15] @pytest.fixture def five_otu(DATA_DIR: pathlib.Path) -> Alignment: aln = load_aligned_seqs( DATA_DIR / "example.fasta", moltype="dna", ) aln = aln.take_seqs(["Human", "Chimpanzee", "Rhesus", "Manatee", "Dugong"]) return aln.omit_gap_pos(allowed_gap_frac=0) @pytest.fixture def all_otu(DATA_DIR: pathlib.Path) -> Alignment: aln = load_aligned_seqs( DATA_DIR / "example.fasta", moltype="dna", ) return aln.omit_gap_pos(allowed_gap_frac=0) @pytest.fixture def protein_four_otu(DATA_DIR: pathlib.Path) -> Alignment: aln = load_aligned_seqs(DATA_DIR / "protein.fasta", moltype="protein") aln = aln.take_seqs(sorted(aln.names)[:4]) aln = aln.omit_gap_pos(allowed_gap_frac=0) return aln[::15] @pytest.fixture def five_trees() -> list[PhyloNode]: tree1 = make_tree("(a,(b,(c,(d,(e,f)))))") tree2 = make_tree("(a,(b,(c,(d,(e,f)))))") tree3 = make_tree("((a,b),(c,(d,(e,f))))") tree4 = make_tree("(((a,b),c),(d,(e,f)))") tree5 = make_tree("((((a,b),c),d),(e,f))") return [tree1, tree2, tree3, tree4, tree5] @pytest.fixture def four_taxon_unrooted_tree() -> PhyloNode: # Unrooted return make_tree("((a:0.1,b:0.2):0.05,c:0.3,d:0.1);") @pytest.fixture def five_taxon_rooted_tree() -> PhyloNode: # Rooted return make_tree("(((a:0.1,b:0.2):0.05,(c:0.3,d:0.1):0.2):0.05,e:0.4);") iqtree-piqtree-b8a3d6a/tests/data/000077500000000000000000000000001521173175100172225ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/tests/data/example.fasta000066400000000000000000005102501521173175100217000ustar00rootroot00000000000000>FlyingFox TGTGGCACAAATGCTCATGCCAGCTCTTTACAGCATGAGAAC---AGTTTATTATACACTAAAGACAGAATGAATGTAGA AAAGACTGACTTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAACAGAACAGATGGGTTGAAACTAAGGAAA CATGTAACGAT---ATGCAGACTTCCAGCACAGAGAAAAAGGTAGTTCTGAATGCTGATCCCCTGAATGGGAGAATAGAA CTGAATAAGCAGAAACCTCCATGCTCTGACAGTCCTAGAGAT---TCTCAAGAT---ATTTCTTGGATAACACGGAATAG TAGCATACAGAAAGTTAATGAGTGGTTTTCCAGACGTGATGAAATATTAACTTCTGATGTCTCACCTGATGGGAGGTCTG AATCAAATGTG---------------GTAGAAGTTCCAAAT------GAAGTAGATGGATACTCTGGTGCTTCAGAGAAA ATAGCTTTAAAGGCCAATGATCCTCATGGTGCTTTAATGTGC------GAAAGAGTTCACTCCAAACTGGTAGAAAGTAA T---ATTGAAGATAAAATATTTGGGAAAACATATCGGAGGAAAGCAAGCCTCCCTAACTTGAGCCACATAACTGAAAATC TAATTACAGGAGCATCTGCTATAGAACCTCAGATAACACAA--------------------------------------- ---------------------GAGTATCCCCTCACAAATAAACTAAAGCGTAAAAGGAGAACTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAATAGATTTGGCAGTTGTTCAGAAAACTCCGGAAAACATAATTGAGGAAACTGACCAAATAG AGCAGAAT---------GGTCATGTGATGAATAGTACTAATAATGGTCATGAGAATGAAACAAAAGGTGATTAT---GTT CAGAAGAAGAAAAATACAAACCCAACAGAA------TCATTGGAAAAAGAATCTACTTTCAAAACTAAAGCTGAACCTAT ATGCAGCAGCATAAGCAATATGGAACTAGAATTAAATATCCACAGTTCAAAAGCAGTTAAGAAGAATAGGCTGAGGAGGA AGTCCTCTACCAGGCATATTCATGCACTTGAACTAGTAGTCAATAGAAATCCAAGCCCACCTAATCATACTGAACTACAA ATTGATAGTTGTTCTAGCAGTGAAGAG---CTGAAGGAAAAA---AATTCTGACCAAATGCCAGTCAGACACAGCAAAAA ACTTCAATTCATAGAAGATAAAGAATCTTCAACTGGAGCCAAGAAGAATAACAAGCCAAATGAGACAATCAATAAAAGAC TTGCCAGTGATGCTTTTCCAGAATTAAATATAACAAACATACCTGGTTTTTTTACTAATGGTTCAAGTTCTAATAAACTT CAAGAGTTTGTCAATCCTAGCCTTCAAAGAGAAGAAATAAAAGAGAAC---CTAGGAACAATTCAAGTGTCTAATAGTAC CAAGGACCCCAAAATTTTGATCTTCGGTGAAGGAAGA---GGTTCACAA---ACTGATCGATCTACAGAGAGTACCAGTA TTTTATTGGTGCCTGAAACGGATTATGGCACTCAAGATAGTATCTCATTACTGGAACCTGACATCCCAGAG---AGGGTA AAG---ACAGCACCAAACCATCAT------------GCAGCAATTAAAAACCCCAGAGAACTTATTCATGGTTGT---TC TGAAGATACTAGAAATGATGCAGAGGGCTTTAAAGATCCATTGAGACGTGAAGTTAAC---TACANNNNNNNNNNN---- -----NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNTTCAAACCCAGGAAATCTAGAAAAGGAATGTGCAACAGGCTATGCCCACTCCAAGTCCTTGAGGAAACAAAGTCCAAA AGTCACTCTTGAATGTGACCGAAAAGAA---AATCAGGGAAAGAAAGAGTCTAACGTCAAGCATGTGCAGGCAGTTTATA CAACTGTAGGCTTTCCTGTGGTTTGTGAGAAAGAAAAAAAGCCAGGAGATTATGCTAAATATGGCATAAAAGAAGTCTCT AGGCTTTGTCAGTCATTTCAGTTCAGA---GAAAATGAAACTGAACTCACTATTGCAAATAAACTTGGAATTTCACAAAA CCCATATCATATGCCATCCATTCCTCCCATCAAGTCATCTGTTAAAACTACATGTAAGAAAAAT---CTGTCAGAGGAAA AGTTTGAAGAACATTCAATATCCCCTGAAAGAACAATAGGAAATGAGACCATCATTCAAAGTACAGTGGGCACAATTAGC CAAAATAACATTAGAGAAAGCACTTTTAAAGAAGGCAGCTCAAGCAGTATTTATGAAGCAGGTTCCAGTACTAACGAACT AGGCTCTAGTGTCAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTCAAGCAGAACTAAGTA GAAACAGAGGACCACAATTAAATGCTGTGCTTCAATTGGGTCTCATGCAGCCTGAAGTCTATAAGCAAAGCCTT---CCT CTAAGTAATTGTAAACATCCTGAAATAAAAAGGCAAGGAGAAAATGAAGGAGTAGTTCAGGCTGTTAATGCAGATGTCTC TCTACGTCAGATTTCAGATAACTTAGAGCAA---CCTATGGGAAACAGTAATGCTTCTCAGGTTTGTTCTGAGACACCGG ATGACCTGTTAAATGATGACAAAATAAAAGAGAATATCGGCTTTGATGAAAGTGGCATTAAGGAAAGATCTGCTGTTTTT AGCAAAAGTGTCCAGAAAGGAGAATTCAAAAGGAGCCCTAGTCCCTTAGCCCAT---ACAAGTTTGTCTCAAGGTCGCCG AAGAGGGGCTAGGAAATTAGAGTCCTCAGAAGAGGA------------- >DogFaced TGTGGCACAAATACTCATGCCAACTCATTACAGCATGAGAACAGCAGTTTATTATACACTAAAGACAGAATGAATGTAGA AAAGACTGACTTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAGCAGAACAGATGGGTTGAAACTAAGGAAA CATGTAATGAT---AGGCAGACTTCCAGCANAGAGAAAAAGGTAGTTCTGAATGCTGATCCCCTGAATGGAAGAATAAAA CTGAATAAGCAGAAACCTCCATGCTCTGACAGTCCTAGAGAT---TCCAAAGAT---ATTCCTTGGATAACACGGAATAG TAGCATACAGAAAGTTAATGAGTGGTTTTCCAGACGTGATGAAACATTAACTTCTGATGTCTTACTTGATGAGAGGTCTG AATCAAATGTG---------------GTAGAAGTTCCAAAT------GAAGTAGATGGATACTCTGGTGCTTCAGAGGAA ATAGCCTTAAAGGCCAGTGATCCTCATGGTGCTTTAATATGT------GAAAGAGTTCACTCCAAATTGATAGAAAGTAA T---ATTGAAGATAAAATATTTGGGAAAACATATCGGAGGAAAGCAAGCCTCCCTAACTTAAGCCACATAACTGAAAATC TAATTACAAGAGCATCTGCTACAGAACCTCAGATAACACAA--------------------------------------- ---------------------GAGTGCCCCCTCACAAATAAACTAAAACGTAAAAGAAGAACTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAATAGATTTGACAACTGTTCAAAAAACTTCTGAAAATATAATTGAGGGAACTGACCAAATAG AGCAGAAT---------GGTCATGTGATGAATAGTTCTAATGATGGTCATGAGAATGAAACAAAAGGTGATTAT---GTT CAGAAGAAGAAAAATACAAACCCAACAGAA------TCATTGGAAAAAGAATCTGCTTTCAGAACTAAAGTTGAGTCTGT ACCCAACAACATAAGCAATGTGGAACTAGAATTAAATATTCACGGTTCAAAAGCACTCAAGAAGAATAGNCTGAGGAGGA AGTCCTNTACCAGGCATATTCATGCACTTGAACTAGTAGTCAATAGAAATTCAAGCCCACCTAATCATACTGAACTACAA ATTGATAGTTGTTCCAGCAGTGAAGAA---CTGAAGGAAAAA---AATTCTGACCGAATGCCAGACAGACACAGCAAAAA ACTTCAGTTCGTAGAAGATAAAGAATCTGCAACTGGAGCCAAGAAGAATAACATGCCAAATGAGGCAATAAATAAAAGAC TTTCCAGTGAAGCTTTTCCCGAATTAAATATAACAAACGTACCTGGTTTTTTTACTAATGGTTCAAGTTCTAATAAACGT CAAGAGTTTGTCAATCCTAGCCTTCAAGGAGAAGAAATAAAAGAGAAT---CTACGAACAATTCAAGTGTCTAATAGCAC CAAAGACCCCAAAATTCTAATCTTTGGTGAAGGAAGA---GGTTCACAA---ACTGATCGATCTACAGAGAGTACCAGTA TTTTATTGGGACCTGAAACGGATTATGGCACTCAAGATAGTATCTCATTACTGGAATCTGACATCCCAGGG---AGGGCA AAG---ACAGCACCAAACCAACATGCAGATCTGTGTGCAGCAATTGAAAACCCCAGAGAACTTATTCATGATTGT---TT TAAAGAAACTAGAAATGACACAGAGAGCTTTAAAGATCCATTGAGACATGAAGTTAAC---TCCACNNNNNNNNNN---- -----NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNTTCAGACCCAGGAAATCTAGAAAAGGAATGTGCAACAGGCTATGCCCACTCCAGGTCCTTGATAAAACAAAGTCCAAA AGTCACTCTTGAATGTGACCGAAAAGGA---AATCAGGGAAAGAAAGAGTCTAACATNGAGCATGTGCAGGCAGTTTATA CAACTATAGGCTTTCCTGGGGTTTCTGAGAAAGACAAAAAGCCAGGAGATTATGCCAGATATGGCATAAAAGAAGTCTCT AGGCTTTGTCAGTCATTTCAGTCTAGA---AGAAATGAAACTGAGCTCACTATTGCAAATAAACTTGGACTTTCACAAAA CCCATATCATATGCCATCCATTTCTCCCATCAAGTCATCTGTTAAAACTATATGTAAGAAAAAT---CTGTCAGAGGAAA AGTTTGAAGAACATTCAATATTCCCTGAAAGAGCAATAGGAAATGAGACCATCATTCAAAGTACAGTGGGCACAATTAGC CAAAATAACATTAGAGAAAGCACTTTTAAAGAAGGCAGCTCAAGCGGTATTTATGAAGCAGGTTCCAGTACCAATGAACT AGGCTCTAGTGTCAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTCAAGCAGAACTAAGTA GAAACAGAGGACCAAAATTAAATGCTGTGCTTCAGTTGGGTCTCATGCAGCCTGAAGTCTATGAGCAAAGCCTT---CCT CTAAGTAATTGTAAACATTCTGAAATAAAAAGGCAAGGAGAAAATGAAGGAGTGGTTCAGGCTGTTAATGCAGATGTCTC TCCANGTCAAATTTCAGATAACTTAGAGCAA---CCTATGGGAAACAGTAATATTTCTCAGGTTTGTTCTGAGACACCGG ATGACCTGTTAAATGATGACAAAATAAAGGACAATATCAGCTTTGATGAAAGTGGCATTCAGGAAAGATCTGCTGTTTTT AGCAAAAATGTCCAGAAAGGAGAATTCAGAAGGAGCCCTAGTCCCTTAGCCCAT---GCAAGTTTGTCTCAAGGTCGCCC AAGAAGGGC---------------------------------------- >FreeTaile TGTGGCACAGATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTACTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAGCAGCCTGGCTTAGCAAAGAGCCAGCAGAGCAGATGGGCTGAAAGTAAAGAAA CATGTAATGAT---AGGCAGACTCTCAGCACAGAGAAAAGGGTAGTTCTGAATGCTGATCCTCTGAATAGG--------- ------AGAAAAGAACCTCCAGGCTCTAACTATCCTAGAGAT---TCCCAAGAT---GTTCCTTGGATAACACGGAGTAG TAGCATACAGAAAGTTAATGAGTGGTTCTCCAGACGTGATGAAATACTAACTACTGGTGGCTCACATAACGGTAGATTTG AATCAAATGTTGAAGTAGCTGGTGCAGTAGAAGTTCCAAAT------GAAGTAGATGGATATTCTGGTTCTCCAGAGAAA ATAGCCTTAATGGCCTGTGATCCTCCTGATGCTTTAATATGT------GAAAGAGTCTCCTCTAAACCACTAGAAAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGAAAGGCAAGCTTCCCTAACTTGAGCCACATAAGTGAAAATC TAATTATAGGAGCATCTGCTATAGAACCCCAGGTAACAAAA--------------------------------------- ---------------------GAATGTCCCCTCACAAATAAACTAAAGCGTAAAAGAAGA---ACATCAAGCCTTCATCC TGAGGATTTTATCAAGAAAGTAGATTTGGCAGTTGTTCAAAAGACTCTTGAAAAGGTAATTGAGGGAACTGACCAAATAG AACAGAAT---------GGTCATGTGATGAGTATTACTAGTAATTGTCATGAGAATAAAACAAAAGGTGATTAT---GTT CAGAAAGAGAAAAATTCTAACCCAACAGAA------TCATTGGAAAAAGAATCTGCTTTCACAACTAAAGCTGAACCTAT AAGCAGCAGCATAAGCAATATGGAACTAGAGTTAAATATCCACAGTTCAAAAGCACCTAAGAAGAATAGGCTGAAGAGGA AGTCCTCTACCAGGCACATTTATGCACTTGAACTAGTAGTCAATAGAAATCCAAGCCCACCTAATCACACTGAACTACAA ATTGATAGCTGTTCTAGCAGTGAAGAG---GTGAAGGAAAAA---AATTCTGACCAAATACCAGTCAGACACAGCAAAAA GCTTCAACTCATGGAAGGTAAAGAACCTGCAACTGGAGCCAAGAAGAGTAACAAATCAAATGAACAAATAAATAAAAAAC TTGCCAGTGATGTTTTTCCAGAACTAAACTTAACAAACATACCTGGTTTTTTAAGTAATGATTCAAGTTCTAATAAACTT AAAGAGTTTGTCAATCCTAACCTTCAAAGAGAAGAAATAACAGAGAAC---CTAGGAACAGTTCACATGTCTAATAGTAC CAAAGACCTCAAAGATCTGATATTAAGTGGAGGAAGA---AGTTTGCAA---ACTGATAGATCTATGGAGAGTACCAATA TTTTATTGGTACCTGAAACTGATTATGGCACGCAGGATAGTATCTCATTACTGGAACCTGACACCCCAGGG---AAGGCA AAA---AAAGCTCCAAATCAATATGCGGGTCTGTGTGCAGAAATTAAAAACCNCAAGGAACTTATCCATGGTTGT---TC TAACGATAATAGAAATGACAGAGAGGACATTAAGGATCTATTGAGACCTGAAGTTAAC---CACANNNNNNNNNNNNNNN NNNNNNNGGAAGAGAGTGAACTTGATACACAGTATTTACAGAATACATTCAAGGTTTCAAAACGTCAGTCGTTTGCTCTG TTTTCAAATCCA---------GAAAAGGAATATGCAACAGTCTATGGCCACTCCAGGTCCTTAAGGAAACAAAGTCCAAA AGTCACTCTTGAATGTGGACAAAAAGAAGAAAATCAGGGAGAGAAAGAATCTGAAATCAAGTATGTACGGGGAGTTCACA CAACTGCAGGCTTTCCTGTGGTTTGTGAGAAAGACGAAAAGCCAGAAGAATATGCCAAATGTAGCATAAAAGGAACCTCT AGCCTTTGTCAGCCACCTCAGTTCAGA---GGCAACGAAACTGAACTCACTATTGCAAATAAACCCGGAATTTCACGAAA CCCATATCATATACCATGCATTTCTCCCATCAGGTCCTTTGTTAAAACTATAAATAAGAAAAAC---CTGTCAGAGGAAA AGTTTGAGGAACATTCAGTGTCACCTGAAAGAGCAATGAGAAATGAGAAT---ATTCTAAGTACAGTGAGCCCAATTAGC CTAAATAAC---AGAGAAAGCACTTTTAAAGAAGGCAGCTCAAGC---------------------AGTACTAATGAAGT AGGCTCTAGTACCAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTCAAGCAGAACTAGGTA GAAACAGAGGATCAAAAATAAATGCTATGCTCAGATCAGGTCTCATGCAACCTGAAGTCTATAAGCCAAGCCTT---TCT GTAAGTAATTGTGAACATCCTGAAATAAAAAGGCAAGGAGAAAATGAAGGAGTAGTTCAGGCTGTTAATGCAGATTTCTC TCCATGTCAAATTTCAGATAACTTAGAACAA---TCTATGGGAAGTACTCCTGCTTCTCAGGTTTGTTCTGAGACACCAG ATGACCTGTTAAATGATGACAAAATAAAGGAGAATAGCAGCTTTGCTGGAAGTGGCATTAAGGAAAGATCTGCTATTTTT AGCAAAAGTGTCAAGAAAGAAAAATTCAGAAGGAGCCCTAGCCCCTTTGCCCAT---ACACATTTGACTCATACTCGCCA AAGAGGGGCCAGGAAATTAGAGTCCTCAG-------------------- >LittleBro TGTGGCACAGATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTACTACTCACCAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAGCAGCCTGGCTTAGCAAGGAGCCAGCAGAGCAGATGGGCTGAAAGTAAAGAAA CATGTAATGAT---AGGCAGACTCCCAGCACAGAGAAAAGGGTAATTCTGGATGCTGATCCTCTGAATGGG--------- ------GAAAAAGAACTTCCACGCTCTGACCATCCCAGAGAT---TCCCAAGAT---GTGCCTTGGATAACACGGAGCAG TAGCATACAGAAAGTTAATGAGTGGTTTTCCAGGCGTGATGAAATACTAACTTCTGATGGCTCACATAATGGCAAGTCTG AGTCAAATGCTGAAGTAGCTGGTGCAGTGGAAGTTGCAAAT------GAAGTAGATGGGTATTCTGGTTCTCCAGGGAAA ATAACCTTAATGGCCCATGATCCTCATGGTGCTTTAACCTGTGAAAGTGAAAGAGTTCACTCCAAACCAGTAGAAAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCAAACTTGAGCCACATAACTAAAAATC TAATTGTAGGAGCATCTGCTATAGAACCTCAGATAGCACAA--------------------------------------- ---------------------GAGTGTCCCCTCACAAATAAACTAAAGCGTAAAAGGAGAAGTACATCNGGCCTTCATCC TGAGGATTTTATTAAGAAAGTAGATTTGGCAGTTGTTCAAAAGACTCCTGAAGAGATAATTAAGGGAACTGACCGAATAG AACAGAAT---------GGTCATGAGATGAATATTACTAATAATGATCATGAGAATGAAACAAAAGGTGATTGT---GTT CAGAAAGAGAAAAATGCTAACCTAACAGAA------TCACTGGAAAAAGAATCTGCGTTCACAAGTAAAGCTGAACCTAT AAGCAGCAGCATAAGCAATATGGAACTAGAATTAAATGTCCACAGTTCAAAAGCACCTAAGAAGAATAGGCTGAAGAGGA AGTCCTCTACCAGGCCTATTCATGCACTTGAACTAGTAGTCAATAGAAATCCGAGCCCATCTAACCATACTGAACTACAA ATTGATAGTTGTTCTAGCAGTGAAGAG---GTGAAGGAAAAA---AATTCTGACCAAATACCAGTCAGACACAGCAAGAA GCTTCAACTCATGGAAGGTAAAGAACCTGCAGCTGGAGCCAAGAAGAGTAATAAGTCAGATGAACAAATAAATAAAAAAC TTGCCAGTGATGCTTTTCTAGAACAAAACTTAACAAACATGCCTGGTGTTTTTACTAATGGTTTAAGCTCTAATAAGCTT AACGAGTTTGTCGATCCTAACCTACAAAGAGAAGAAACAGAAGAGAAC---CTAGGAGCAGTTCAAATGTCTAATAGTAC CAAAGACCTCGAAGATCTGACATTAAGTGGAGGAAGA---AGTGTGCAA---ATTGATAGATCTAAAGAGAGTACCAATA TTGTATTGGTACCTGAAACTGATTATGGCACACAGGATAGTGTCTCATTACTGGAACCTGACATCCCAGGG---AAGGCA AAA---ACAGCTCCAAATCAATGTGGGGATCTGTGTGCAGCAGTTAAAAATCCTAAAGAACTTATTCGTGGTTGT---TC TAAAGATATTAGAAATGACAGAGAGGGCTTTAAGGATCTATTGAGATGTGAAGTTAAC---CACACGCAGGAGACAAGCA TAGAAGTGGAAGAGAGTGAACTTGATACACAGGAATTACAGAATACATTCAAGGTGTCAAAGCGCCAGTCATTTGCTCTG TTTTCAAATCCA---------GAAAAGGAATGTGCAACAGCCTATGCTCACTCCCAGTCTTTAAGGAAACAAAGTCCAAA AGTCACTCTTGAATGTGGACAAAAAGAAGAAAATCAGGGAAAGAAAGAATCTAAAATCAAGCATGTACAGGCAGTTCACA CAGCTGTAGGCTTTCCTGTGGTTTGTGAGAAAGACAGAAAGCCAGGAGAGTATGCCAAATACAGCATAAAAGGAACCTCT ATGCATTGCCNGTCCTCTCAGTTCAGA---GGCAACAAAACTGAACTCACTATTACAGATAAATATGGACTTTCCCCAAA CCCATATCATATACCATCCATTTCTCCCATCAAGTCATTTGTTAAAACTGTAAGTAAGAAAAAC---CTGTCAAAGGAAA AGTTTGAGGAACATTTAGTGTCACCTGAAAGAGCAATGGGAAATGAGAAC---ATTCAAAGTACAGTGAGCCCAATTAGC CTAAGTAACATTAGAGAAAGCGCTTTTAAAGAAAGCAGCTCAAGC---------------------AGTACTAATGAAGG GGGCTCTAGTATCAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTCATGCAGAACTAGATA TAAACAAAGGATCAAAATTAACTGCTATGCTCAGATTAGGTCTCATGCAACCCGAAGTCTATAAGCCAAGCCTT---CCT GTAAGTAATTGTAAACATCCTGAAGTAAAAAGGCAAGGAGACAACGAAGGACTAGTTCAGGCTGTTAATGCAGACTTCCC TCCATGTCAAATTTCAGATAACCTAGAACAA---CCTATGGGAAGTAGTCCTGTTTCTCAGGTTTGTTCTGCGACACCGG ATGACTTGTTAACTGATGATGAAATAAAGGAGAATAGCGGCTTTGATGAAAGTGGCATTAANGAAAGATCTGCTGTTTTT AGCAAAGATGTTCAGAAAGAAGAATTCAGAGGGAGCCCTAGCCCCTTAGCCCAT---ACATATTTGACTCGGAGTTGCCA AAGAAGGGCCAGGAAATTAGAGTCCTCAGAAGAGGA------------- >TombBat TGTGGCACAAGTACTCATGCCAGCTCAGTACAGCATGAGAACAGCAGTTTACTACTCACTAAAGACAGAATGAACGTAGA AAAGCTTGACTTCTGTAATAAAAGCAAGCAGCCTGGCTTAGCAAGGAGCCAGCAGAGCAGATGGGCTGAAAGTAAAGAAA CATGTAATGAT---AGGCAGACTCCCAGCACAGAGAAAAGGGTAGTTGTGAATGCTGATACCCTGGATGGG--------- ------AGAAAAGAACCTCCATACTCTGACTGTCCTAATGAT---TCCCAAGAT---GTCCCTTGGATAACAGGGAATAG TAGCATACAGAAAGTTAGTGAGTGGTTTTCCAGGCGTGATGAAATATTAACTTCTGATGGATCACATGATGGGAGATCTG AATCAAATATGGAAGTAGCTGGTGCAGTAGAAGTTCCATAT------GAAGTAGATGGATATTCTGATTCTCCAGAGAAA ATAGGCTTAATGGCCAGTGATCCTCTTGGTGCTTTACTATGTGAAAGTGAAAGAATCCACTCCAAACCAGTAGAAAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCTAACTTGAGCCATATAACTGAAAATC TAATTATAGGAGCACCTACTATACAATCTCAGATAACACAA--------------------------------------- ---------------------AATTGTCCCCTCACAGATAAACTAAAGCATAAAAGAAGAACTACATCAGGCCTTCGTCC TGAGGATTTTATCAAGAAGGTAGATTTGGCAGCTGTTCAGAAGACTCCTGAAAAGATAATTGAGGGAACTGATCAAACAG AACAGAAT---------GGTTCTGTGATGAATATTACTGATAATGGTCATGAGGATGAAACAAAATGTGATTAT---GGT CAGAAAGAGAAAAATGCTAACCCAGCAGAA------TCATTGGAAAAAGAATCTGCTTTCAGAACTAAAGCTGAACCTAT AAGCAGCAGCATAAGCAACATGGAACTAGAGTTAAATATCAACAGTTCAAAAGCACCTAAGAAGAATAGACTGAGGAGGA AGTCCTCTACCAGGCATATTTATGCACTTGAACTGGTAGTCAATAGAAATCCAAGCCCACCTAATCATATTGAACTACAA ATTGATAGTTGTTCTAGCAGTGAAGAG---GTGAAGAAAAGA---AATTCTGACCAAATACCAGTCAGGCACAGCAAAGA GCCTCAACTCGTGGAAGGTGAAGAACCTACGACTAGAGCCAAGAAG---AATAAGTCAAATGAACAAATAAATAAAAGAC TTGCCAGTGATACTTTTCCAGAACTAAATTTAAAAAACATACCTGGTTTTTTTACTAATGGTTCAAGTTCTAATAAACTT CAAGAGTTTGTTGATCCTAACCTTCGAAGAGAAGAAGTGGAAGAGAAC---CTAGGAACAATTCAAGTGTCTGATAGTAC CAAAGACCTCAAAGATCTGATATTAAGTGGAGGAAGA---AGTTTGCAA---ACTGATAGATCTATGGAGAGTACCAATA TTTTATTGGTACCTGAAACTGATTATGACACTCAGTATAGTATCTCATTACTGGAACCTGACACCCCAGGG---AAGGCA AAA---ACAGCACCAAGTCAACATGCGAGTCTGTGTGCAGCAATTGAAAACCCCAAGGAGTTTAACCATGGTTGT---TC TAAAGATACTAGAAGTGACACAGAGGGTGTTAAGGATCTACTGAGATGTGAAATTAAC---CNCACNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNGAATACATTCNNGNTTTCAAAGCGTCAGTCATTTGCTCTG TTTTCAAATTCAGAAAATCCAGAAAAGGAATGTGCAACAGTCTATGCCCACTCCAAGTCCTTAAGGAAACACAGTCCAAA AGTCACTCTTGGATGTGGTCAAAAAGAAGAAAATCAGGAAGAGAAAGAATCTAAAATCAAGCATGTACAGGCTGTTCACA CAGCTGCAGGCCTTCCTGCCATTTGTGAGAAAGACAAGAAGCCAGGAGAATATGACAGATACAATATAAAAGGAATCTCT AGGCTTTGTCAGTTATCTCAGTTCAGA---GGCAATGAAACTGAACTCACTATTGAAAATAAACACAGAATTTTACAAAA CCCATATCATATATCACCCATCTCTCCCATCAGGTCATCTGTTAAAACGATAAGTAAGAAAAAC---CTGTCAGAGGAAA AGTTTGAGAAACAGTCAGTGTCACCTGAAAAAGCAATGGGAAATGAGAACATCATTCAAAGTACAGTGAGCACAATTAGC CAAAATAATGTTAGAGAAAGAGCTGTTAAAGAAGGCAGCTCAAGC---------------------AGTACTAACGAAGT AGGCTCTAGTATCGATGAAGCAGGTTCCAGT---------------------GGTAAAAACATTGGAGCAGAACTAGATA GAAACAGAGGATCAAAATTAAGTGCTGTTCTCAGATTAGGTCTCATGCAACCCGAAGTCTATAAGCCAAGCCTT---CCT ATAAGTAATTGTAAACACTCTGAAATAGAAAGGCAAGGAGAAAATGAAGTAGTAGTTCAGGCTGTTAATGCA-------- ----TGTCAAATTTCAGATAACTTAGAACAG---CCTATGGGAAGTAGTCCTGTTTCTCAGGCTTGTTCTGAGACACCAG ATGACCTATTAGATGATGACAAAATAAAGGAGAATAGCAGCTTTGCTGAAAGTGGCATTAAGGAAAGATCTGCTATTTTT AGCAAAAGTGCCCAGGAA---GAACTCAGCAGGAGCCCTAGCCCCTTAACCCAT---ACACATTTGGCTCAGGGTCAGCA GAGAAGGGCCGGGAAATTAGAGCC------------------------- >RoundEare ---------------------NGCTCATTANAGCNTGAGAACAGCAGTTTACTGCTCACTGAGGACCAGATGAGTGTGGG AAAGGCTGAATTCCGTCATGAAAGCAAGCAGCCCGGCTTAGCGAGGAGCCAGCAGAGCAGATGGGCTGAAAGTAAAGAAA CATGTGACGAT---AGGCAGGCTCCCAGCGCAGAGGAAAGGGCAGTTCTGAATGCTGATCCCCAGAATGGG--------- ------AGGGAAGAATCTCCATCCTCTGACCACCCTAGAGAT---TCCCAAGAT---GTTCCTTGGATAACACGGAATAG CAGCATACAGAAAGTTAATGAGTGGTTTTCCAGACGTGATGAAACACGGACTTCCAACGGCTCCCACGGTGGGAGGCCTG AGTCAGACACGGAAGGAGCCGACACGGTAGAAGCTCCGGAC------GAAGTGCGTGGATGCCCTGGCTCTCCAGAGAAC ACAGCCTCGCCGGCCGGCGAGCCTCATGGCGCTTTAATGTGCGGAAGTGAAAGCGTCCACTCCAAACCAGTGGAGAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCTAACTTGAGCCACGTAACTGACAGGC TAACTACGGGACTGTCCGCTCCAGACCCTCAGATAACACGA--------------------------------------- ---------------------GAGCGTCCCTTCACCAACAAACTAAAGCGTAAAAGGAGAACTACACCGGGCCTTCACCC AGAGGATTTTATCAAGACAGTGGATTTGACCGTTGTCCAGAAGACTCCTGAGAAGACCATTGAGGGAACTGACCAAACAG AACAGAAC---------GGTCGTGTGATGGATATTGCTAACAGTGGTCACGGGAATGAAGCAAAAGGTGATTAT---GTT CAGAATGAGAAGAGTTCTGACCCAACAGAA------TCACTGGGAGAAGAACCCGCTTTCAGAACTAAAGCTGGACCTAT AAGCAGCAGCATAAGCACCGTGGGACTAGAATTGAATGTCCACGGTTCAAAAGCGCCCAGGAAGACTAAGCGGAGGGAGA AGACTGCTGCCGAGCATACTTATGCACCTGGACTCGGGGTCAGCAAGAGCCCGAGCCCCCCTGCTCACGCCGGACTGCGG ACGGACGGTTGTTCTGGCGGCGAGGAG---GCAAAGATCGGG---AATTCTGGGCAGAGGCCAGCCAGGCGGAGCAGCAA GCTTCCGCTCGAGGAGGGTCAGGAGCCTGCAGCTGGGGCCAGCAAGGGTGACCGGTCAGATGCACCGATGAATAAGAGAC TTGCCAATGATGCTTTTCCGGAACTAAATTTAACAAGCGTATCTGCCGTTTTTACTAATGGTTCAGGTTCTACTAAACTT AAAGAGTGTGTCGATTCTAACCCTCAAGGAGAAGACACAGAAGAGAAC---CGAGGAACAGTTCAAGTGTCTAGTAGCAC CAAAGACCTCAAAGATCTGATATTCAGTGGGGGAAGA---AGTTTGCAA---ACTGACAGATCTGTGGAGAGTCCCAATA TTGNATTGGTACCTGAAACTGACTGTGACACTCAGGATAGCGTCTCCCTGCTGGCACCTGACACCCCAGGG---AAGGCA GAA---ACAGCACCAGGCCAACGTGTGGGTGGGTGCGCAGCTGCTGGAAGCCCGAAGGAACTTATCCGTGATTGT---TC GAAG------------GACACAGAGGGCGTTAAGGATCTCCCGAGATGTGAAGTTCAG---GAGACNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNTGCTCTG TGTTCAAATCCAGGNAATCCAGGAAAGGAATGTGCAACCATGTATTCCCACTCCAGGTCCACAAGGAAACGAAGTCCAAA AGTTACTCTTGAATGTGGACGAAAAGAA---CATCAGGGAGAGAAGGAATTTAATATGGAGCGTGCGCAGCCACCTTACA CAACAGCAGGCTTTCCTAAGGGTTGTGAGAAAGACAAAACGCCAGGAGAGTGTGCCACATATACTATGAAAGGAATCTCT AAGCCTTGTCAGTCATCTTCGTTCAGA---GGCAATGAAACTAAACTCACTATTGAAAATAAATATGGGATTTCACAAAA CCCCTATCACATACCACCCATTTCTCCCGTCAGGTCATCTGTTAAAACTACAAGTAAGAAGAAC---CTGTCAGAGGAGA AGTGTGAGGAACATTCAGTGTCACCTGCCAGAGCCGTGGGACGTGAGAACATCATTCAGAGTACAGCGGGCACTCCTAGC CAGAACAAAACCAGGGAAAGTGCCGCCAGAGAAGGCAGCTCGAGC---------------------GGCACTAACGAAGT AGGCTCCAGT------------------------------------------GGTGAAAACGGTCAAGCAGAGCCAGGCA CAAACAGAGCATCAAAATTAAGCGCTCTTCTCAGATCAGGGCTCATGCAACCTGAAGTCTGTAAGCCGAGTCTT---CCT CTGAGTAATTGTGAAGATCCTGAAATAAAAAGGCAA---GAAGATGGGGGAGTAGTGCAGGCTGTTAATGCAGATTTCTC TCCGTGTCAAATTTTAGATAACCTAGAACAA---CCTCTGGGAAGCAGTCCCGCTTCTCGGGTTTGTTCCGAGACCCCAG ACGACCTGTTAAATGATGACAAGGTAAAGGAGGATAACAGCTTTGCTGAAGGCGGCATGAAGGACAGATCTGCTGTTTTT AGCAAAAGCGTCCTGAAA---GAATTCAGAAGGAGCCCCAGTCCCTTAGCCCAC---ACANTCTTGGCTCGGGGTCACCC CAGAAGGGCCAGGAAACTCGAGTCCTCAGAAGAGGA------------- >FalseVamp TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAATTTATTACTGACTGAAGACATAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGTGTTAGCAAGGAGCCAGCAGAGCAGATGGGCTAACAGTAAAGAAA TATGTAATGAT---AGGCAGACTCCCAACACAGAGAAAAGGGTAGTTCTGAATGCTGATCCCTTGAATGAGAGAAAAGAA CTGAATAATCAGAAACCTCTATGCTCTGACAGTCCTAGAGAT---TCCCAAGAC---GTTCCTTGGATAACACGTAATAG TAGCATACAGAAAGTTAATGAGTGGTTTTCCAGACGTGATGAAATACTAACTTCTCATGGTTCACATGATGGGACAGGTG GATCAAATACAGAAGAAGCTGGTGCAGCAGAAATTCTAAAT------GAAGTAGATGGATATTCTGGTTCTTCAGAGAAA ATAGCTTTAATGGCCAGTGATCCTCCTGGTGCTTCAATTTGTGAAAGTGAAAGAGTCTACTCCAAACCAGTAGAAAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTACAGGAGGAAGGCAAGCCTCCCTAACTTGGGCCACAGAGCTGAAAATC TAATTATAGGAGCATCTGCTGTAGAACCTCAGATAATACAA--------------------------------------- ---------------------GAGTGTCTCCTCATAAATAAACTAAAGCGTAAAAGGAGAACTACATCAGCCCTCCATCC TGAGGATTTTATCAAGAAAGTAGATGTGGCAGTTGTTGAAAAGATTCCTGGAGATAGAATCAAGGGAACTGACCAAATAG AGCAGCAT---------GGTCATGTGATGAATATTACTAATTATGGTCATGAGAATGAAACA------------------ ------------AATGCTCACTCAACAGAA------TCACTGGACAAAGAATCTGCTTTTAGAACTAAAGCTGAACCTAT AAGCAGCAGTATAAGTAATATGGAACTAGAATTAAATATCCACAGTTTAAAAGCACCTAAGAAGAATAGGCTGAGGAGGA AGTCCTCTACAAGGCATATTCATGCACTTGAACTA---GTCAGTAGAAATCCAAGCCCACCTAATCATACTGAACTACAG ATTGATAGTTGTTCTAGCAATGAAGAG---GTGGAGAAGAAA---AACTCTGACCAAATGCCAGCCAGACACAACAAAAA TCTTCAACTTATAGAAGATAAAGAACCTGCAACTAGAGCTAAGAAGAGTAACAAGCCAGATGAACAAATAAATAAGAGAC TTACCAGTGATGCTTTTTCAGAACTAAATTTAACAAACACACCTGGTTTTGTTACCAACAGTTCAAATTCTGATAAACTT AAAGAGTTTGTCAATCCTAGCCTTCAAAGAGAAGAAATAGAAGAGCAT---CTGGGAACGATTAAAGTGTCTAATAGTAC CAAAGACCCCAAAGATCTGATACTAAGTGGAGGAAGA---GGTTTGCAA---ACCGATCGTTCTATGGAGAGTACCAGTA TTTCATTGGTACCTGATACTGATTATGGCACTCAGGCTAGTATGTCATTACTGGAACCTGACACCCCAGGG---AAGGTA AAA---ACAGCACCAAATCGACGTGCAGGTGTGTGTGCTGCAATTGAAAACCCCAAGGAAATTATCCATGGTTGT---TC TAAAGATACTAGAAATGACACAGGGGACTTTAAGGATCCACTAAGAGGTGAAGTTAAC---CACACNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NTTTCAAATCCAGGAAATCCAGAAAAGGAATGTGCAACAGTCTGTGCCCACTCCAGTTCCTTAAGGAACGAAAGTCCAAA GGTCACTCTTGAATGTGGACAAAAAGAAGAAAATCACGGAAAGAAAGAGTCCAAAATCAAGCATGTGCAGGCAGTTCCAA CAACTGCAGGCTTTCCTGTGGTTTGTGAGAAAGAAAAAAATCCAGGAGATTATGCCAAATATACCAAAAAAGGAGTCTCT AGGCTTCGTCAGTCATCTCAGATCAGA---GGCAACAAAACCGAACTCACTGTTACAAATAAACATGGAATTTCTCAAAA CCCATATCATATACCACCCATTTCTTCCATCAGGTCATCTGTTAAAACTATATGTAAGGAAAAC---CTGTCAGAGGAAA ACCTTGAGGCATATTTGGTGTCACCTGAAAGAGCAATGGGAAATGAGAGCATTGTTCAAAGTACAGTGAGCACAGTTAGC CAAAGTAACATTAGAGAAAGCACTTTTAAAGAGGGCAGCTCCAGCAATATTTATGAAGCAGATTCCAGTGCTAATGAAGT AGGCTCTAGTATCAGTGAGGTAAGTTCCAGT---------------------GGTGAGAACATTCAAACAGAACTGGGTA GAAACCAAGGACCAAAATTAAATGCTGTGCTCAGATTAGGTCTCATGCAACCTCAAGTCTATGTGCAAAGCCTT---CCT GTAAGCAATTGTGAACATTCTGAAATAAAAAGGCAAGGAGAAAATGAAGGAGTAGTTGAGGCTGTTAATGCAGAATTCTC TCCATGTCAAACTTCAGATAACCTGGAACAA---CCTATGGGAAGTAGTCATGCTTCTCAAATTTGTTCTGAGACACCGG ATGACCTGTTAAACGATTATGAAATAAAGGAAAATGTTAGCTTT---------------AAGGAAAGATCTGCTGTTTTT AGCAAAAGTGTCCAAAAAGAAGAATTGAGTAGAAGCCCTAGCCCCTTAATCCAT---ACATGTTTAGCTCAGGGTCACCG AAGA--------------------------------------------- >LeafNose TGTGGCACAAATACTCATGCCAGCTCTTTACATTATGAGCACAGCAGTTTATTACTCACTGAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAGCAGCCTGGCTTAGCAAGGAGCCAACAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCCAGCACAGAGGAAAATGTAGTTCTGAATACTGATCCCCTGAATGGGAGAAAAGAA CTGAATAAGCAGAAACCTCCATGCTCTGACAGTCCTAGGGAT---TCCCAAGTT---GTTGCATGGATAACACAGAATAG TAGCATACAGAAAGTTAATGAGTGGTTTTCCAGACGTGATGAAATATTAACTTCTCATAGCTCATGTTATGGGAGAGCTG AATCAAATACAGAAGTATCTGGTGCAGTAGAAGTTCCACTT------GAAGTAGATGGATTTTCTGGCTCTACAGAGAAA ATAACCTTAATGACCAGTGATCCTCATGATGCTGTAATATGTGAAAGTGGAAGAGTCCACTCCAAACCATTGGAAAGTAC T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCTAACTTCAGCCACACAACTGAAAACA TAATTATAGGAGCATCTGCTGTAGAACCTCAGATAACACAA--------------------------------------- ---------------------GAGTGTCCCCTCACAAACAAACTAAGGCGTAAGAGGCGAACTACGTCAGGCCTTCATCC TGAGGATTTCATCAAGAAAGTAGATTTGACAGTTGTTCAAAAGACTCCTGAAAAGATAATTGAGAGAACTCACCAAACAG AACAGAAT---------GGTCATGTGATGAACATTACTGATAATGGTCATGGGAATGAAACAAAAGGTGATTAT---GTT CAGAAAGAGGATAATGCTAACCCAACAGAA------TCATTGGAAAAAGAATCTGCTTTCAGAACTACAGCTGAACCTAT AAGCAGCAGTATAAGCCATATGGAACTAGAATTAAATATCCATAGTTCAAAAGCACCTAAGAAAAATAGGCTGAGGAGGA AGTCCTCTACCAGGCCTATTCATGCACTTGAACTAGTAGTCAGTGGAAATCCACGCCCACCTAGTCAGACTGAGCTACAA ATTGATAGTTGTTCTAGCAGTGAAGAG---GTGAAGAAAAAA---ATTTCTGACCAAGTGCCAGTCACACACAGCAAAAC GCTTGAACTCATAGAAGATCAAGAACCTGCAAATGGAGTCAAGAAGAGGAACAAGCCAAATGAACAAATAAATAAGAGAC TTACCAGTAATGCTTTTCCAGAACTAAATTTAACAAACATACCTGGTATATTG---AACCGTTCAAGTTCAAATAAACTT CAAGAGTTTGTCAATCCTAGCCTTCAAAGAGAAGAAATAGAAGAGAGC---CTAGGAACAATTCAAGTGTCTAATAGTAC CAAAGGCCTCAAAGATTTGATATCAAATGGGGGAAGA---GGCTTGCAA---ACTGGTCAATCTATGGAAAGTACCAGTA TTTTATTGGTACCTGATACTGATTATGGCAGTCAGGATAGTATGTCATTACTCGAACCTGACACCCCAGGG---AAGGCA AAG---ACTGCACCAAATCAACATGTGGGTGTATGTACAGCAGTTGAAAACCCCGAGGAACTTATCCATGGTGGT---TC TAATGATACTAGAAATGACACAGAGAGCTTTAAGGATTCATTGAGACATGAAGTTAAC---CACGGTCAGGAGACAAGCA TAGAAATGGAAGAGAGTGAACTTGATACACAGTATTTACAGGAAACATTCAAGGTTTCAAAGCGTCAATCATTTGCTCTG TTTTCAAATCCAAGAAATCAAAGAAAGGAATGTGCAACAATCCAGTCCAGGTCC------TTAAGGAAACAAAGTGCAAA AGTCACTCTTGAATGTGGACAAAAAGAAGAAAATCAGGGAAAGAAAGATTCTAAAATCAAGCTTGTACAGGCAGTTCATA CAACTGCAGGCTATCCTGTGGTTTGTGAGAAAGATGAAAATCCAGGAGATTATGCCAAATACAGCACAAAAGGAGTCTCT AGGCTTTGTCAATCATCTCTGTTCAGA---AGCAACGAAACTGAACTCACTATTGCAAATAAACATGGAATTTCTCAAAA CCCACATAATATACCACATATTTCTCCCATCAGGTCATCTGTTAAAACTGTATGTAAGAAAAAC---CTGTCAGAGGAAA ACTTGGAGGAATATCCAGTGTCACCTGAAAGAGCAATGGGAAATGAGAGCATCATTCAAAGTACAGTGAGCACAATTAGC CAAAATAACATTAGAGAAAGCACTTTTAAAGAAAGCAGCTCAAGCAATNTTTATGAAGCAGATTCCAGTACTAATGAAGT AGGCTCTAGTATCAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTCAAGCAGAACTCGGCA GAAACAGAGGACCGAAATTAAATGCTGTGCTCGGATTAGGTCTCGTGCAACCTGAAGTCTATAGGCAAAGCCTT---CCT GTAAGTAATTGTCAACATCCAGAAATAAAAAGGCAGGGAGAAAATGAAGGAATAGTTCAGGCTGTTAGTGCAGACTTCTC TCCATGTCAAATTTCAGATAACCTAGAACAA---CCTACGGGAAGTAGTCATGCTTCTCAGGTTTGTCCTGAGACACCGG ATGACCTGTTAAATGATAACGAAATAAAGGAAAATGACAGCTTTGCTGAAAGTGACATTAAGGAAAGATCTGCTGTTTTT AGCAAAAGTGTCCAGAAAGGAGAATTCAGAAGGAGCCCTAGCCCCGTAGCTCAC---ACACGTTTGGCTCAGGGTCACCA AAGACGGGCCAGGAAATTAGAGTCCTCAGAAGAGGA------------- >Horse TGTGGCACAAATACTCATGCCAGCTCATTGCAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAAGAGCCAACAGAGCAGACGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGGCCCCCAACTCAGAGGAAAAGCTAGTTCTGAATGCTGATCCGCTGTATGGGAGAGAAGAA CTGAATAAGCAGAAACCTCCACGCTCTGACAGTCCTAGAGAC---TCCCAAGAT---GTTCCTTGGATAACACTGAATAG TAGCATACAGAAAGTTAATGAGTGGTTTTCCAGAAGTGAGGAAATGTTAACTTCTGATGACTCATGTGACGGAGGGCCTG AATCAAATACAGAAGTAGCTGGTGCAGTAGAAGTTCCAAAT------GAAGTACGTGGATATTCTGGTTCTTCAGAGAAA ATAGACTTAATGGCCGGTGATCCTTCTAGTGCTTTAATATGTGAAAGTGAAAGAGTCCGCTCCAAACCAGTAGAGAATAA T---ATTGAAGATAGAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCTTCCCTAACTTGAGCCACATAACTGAAGATC TAATTATAGGGGCATCTGCTATAGAACCTCAGATTACACAA--------------------------------------- ---------------------GAGCGTCCACTCACAAATAGAGTGAAGCATAAAAGGAGAACGTCATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGTAGATTTGGCAGTTGTCCAAAAGACTCCTGAAAAGATAATTGAGGGAACTGACCAAATAG AGCAGAAC---------AGTCATGTGATGAATATTACTCCTAATGGTCATGGGAATGAAACAAAAGGCGATTAT---GTT CAGAATGAGAAAAACGCTTACCTAACAGAA------TCATTGGAGACAGAATCTGCTTTCAGAACTAAAGCTGAACCTAT AAGCAGCAGCATAGGCAATCTGGAACTGGAATTAAATATCCACAGTTCAAAAGCACCTAAGAAGAATAGGCTGAGGAGGA AGTCTTGTACCAAGCAGATTCATGCACTTGAACTAGTAGTCAGTAAAAATCCAAGCCCACCTAATCATACTGAACTACAA ATCGATAGTTGTTCTAGTAGTGAAGAG---ATGAAGAAAAAA---AATTCTGACCAAATGCCGGTCAGACACAGCAAAAA GCTTCAACTCATGGAAGATAAAGAACCTGCCACTGGAGCCAAAAAGAGTAACAAGCCAAATGAACAAATAAATAAAAGAC TTGCCAGTGATGCTTTTCCAGAGCTAAAATTAACAAACATACCTGGTTTTTTTACTAACTGTTCAAGTTCTAATAAACTT CATGAGTTTGTCAATCCTAGCCTTCAAAGAGAAGAAATAGAACAGAAC---CTAGGAGCAAATCGACTGTCTAATAGTGC CAAAGACCCCAAAGATCTGATATTAAGTGGAGGAAAA---TGTTTGCAA---GCTGAAAGATCTGTAGAGAGTTCCGGTA TTTCATTGGTACCTGATACTGATTATGGGACTCAGGATAGTATCTCACTGCTGGAAGCTGACACCCTAGGG---AAGGCA AAA---ACAGCACCAAATCAATGTGCAAATCTATGCGCAGCAATTGAAAACCCCAAGGAACTTACCCATGATTGT---TC TAAGGATACTAGAAATGATACACAGGGCGTTAAGGATCCATTGAGACGTGAAGTTAAC---CACACTCAGGAGACAAGCA TAGAAATGGAAGAGAGTGAATTTGATACGCAGTATCTACAGAATATGTTCAAGGTTTCAAAGCGTCAGTCATTTGCTCTG TTTTCAAATCCAGGAAGTCCAGAAAAGAAGTGTGCAACAGTCAGTGCCCACTCCAGGTCCTTAAGGAAACAAAGTCCAAA AGTCACTCTTAAATGTGGACAAAAAGAAGGAAAGGAGGGAAAGAAAGAGTCTAAAATCAAGAATGTGCAGTCAGTTCACA CAACTGTGGGCTTTCCTGTGATTTGTCAGAAAGATAAGAAGCCAGGTGACTATGTCAAATGTAGCACAAAAGAAGCCTCT AGGCTTTGTCAGTCATCTCAGTTCAGA---GGCAACGAAACNGAACTTATTACTGCAAATAAACATGGAATTTCACAAAA CCCATATTATATACCATCACTTTCTCCCATCAGGTCATCTGTTAAAACTGTATGTCAGAAAAAC---CTGCCAGAGGGAA AGCTTGAGGAACAGTCACTGTCACCTGAAAGAGCAATGGGAAATGAGAGCATTGTTCAAAGTACAGTGAGCACAATTAGC CAAAATAACATTAGAGAAAGCACATTGAAAGAAGTCAGCTCAAGC---------------------AGTATTAATGAAGT AGGCTCTAGTATTAATGAAGTAGGTTCCAGT---------------------GGTGAACACATTCAAGCAGAACTAGGCA GAAACAGAGGACCTAAATTAAATGCTATTCTCAGATTAGGTCTTATGCAACCTGAAGTCTATAAGCAAAGTCTT---CCT ATAAGTAATTGTAAACATCTGGAAATAAAAAGGCAAGGAGAAAAGGAA---GTAGTTCAGGCTGTTAACGCAGACTTTTC TCCGTGTCTAATTTCAGATAACCTAGAACAA---CCTATGGGAAGTAGTTGTGCTTCTCAGGTTTGTTCTGAGACACCTG ATGACCTGTTAAATGATGACGAAATAAAGGAAAATATCAGCTTTGCTGAAAGTGGCGTTAAGGAAAGATCTGCCGTTTTT AGCAAAAGCGTCCAGAAAGGAAAGTTCAGAAGGAGTCCTAGCCCTATAGGCCGT---ACGTGTTTGGCTCAGGGTCACCA AAGACGGGCCAGGAAATTAGAGTCCTCAGAAGAGAACACGTCTAGTGAG >Rhino TGTGGCACGAATACTCATGCCAGCTCATTGCAGCATGAGAACAGCAGTGTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGTGAACAGCCTGGTTTAGCCAAGAGCCAACAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCCAACTCAGAGAAAAAGCTAGTTCTGAACGCTGATCCYCTGTATGGGAGAAAAGAA CTGAATAAGCAGAAACCTCCATGTTCTGACAGTCCTAGAGAT---TCCCAAGAT---ATTCCTTGGATAACACGGAATAG TAGCATACAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGAAATATTAACTTCTGATGACTCACATGATGGGGGGCCTG AATCAAATACTGAAGTAGCTGGTGCAGTAGAAGTTCAAAAT------GAAGTAGATGGATATTCTGGTTCTTCAGAGAAA ATAGGCTTAATGGCCAGTGATCCTCCTGGTGCTTTAATATGTGAAAGTGAAAGAGTCCACTCCAAACCAGTAGAGAATAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCTTAACTTGAGCCACATAACTGAAGATC TAATTATAGGAGCATCTGCTATAGAATCTCAGATTACACAG--------------------------------------- ---------------------GAGCGTCCCCTCACAAATAAACTGAAGCATAAAAGGAGAACTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGTAGATTTGGCAGTTGTCCAAAAGACTCCTGAAAAGATAATTGAGGGAACTGACCAAATAG AGCAGAAC---------GGTCGTGTGATGAGTATTGCTAATAATGGTCATGAGAATGAAACAAAAGGTGATTAT---GTT CAGAAAGAGAAAAATGCTAACCCAACAGAA------TCATTGGAGAAAGAATCTGCTTTCAGAACGAAAGCTGAACCTAT AAGCAGCAGCATAAGCAATCTGGAACTGGAATTAAATATCCACAGTTCAAAAGCACCTAAGAAGAATAGGCTGAGGAGGA AATCCTCTACCAGGCATATTCATGCACTTGAACTAGTAGTCAGTAGAAATCTAAGCCCACCTAATCATACTGAACTACAG GTTGATAGTTGTTCTAGCAGTGAGGAG---ATGAAGAAGAAA---AGTCCCAGCCAGGTGCCAGTCAGACATAGCAGAAA GCTTCAACTCACMGAAGATAAAGAACCCGCAGCTGGAGCCAAGAAAAGTAACAAGCCAAATGAACAGATAAATAAAAGAC TCGCCAGTGATGCTTTTCCAGAACTAAAATTAACAAACGTACCTGGTTTTTTTGCTAACTGTTCAAGTTCTAATAAACTT CAAGAGTTTGTCAATCCTAGCCTTCAAAGAGAAGACATAGAACGGAAC---CTAGGAGCAATTCAAGTGTCTAATAGTAC CAAAGACCCCGAAGATCTGATATTAAGTGGAGGAAGA---GGTTTGCAR---GCTGAAAGATCTGTAGAGAGCACCAGTA TTTCATTGGTACCTGATACTGATTATGGCACTCAGGGTAGTATCTCATTACTGGAAGCTGACACCCTAGGG---AAGGCA AAA---ACAGCACCAGATCAACGTGCAAGTCTATGTGCAGCAATTGAAAACCCCAAGGAACTTATCCATGATTGT---TC TAAAGATACTAGAAATGACACAGAGGGCCTTAAGGATCCATTGAGATGTGAAGTTAAC---CACACTCAGGAGACAAGCA TAGAAATGGAAGAGAGTGAACTTGATACACAGTATCTACAGAATACGTTCAAGGTTTCAAAGCGTCAGTCATTTGCTCTG TTTTCAAATTCAGGAAATCCAGAAAAGGATTGTGCAGCAGTCTCTGCCCACACCAGGTCTTTAAGGAAACCAAGTCCGAA AGTCACTCTTGAATGTGGACAAAAAGAAGAAAATCAGGGAAAGAAAGAGTCTAAAGTCAAGCATGTGCAGTCAGTTCATA CAACTGTGGACTTTCCTGTGGTTTGTCAGAAAGATAAGAAACCAGGTGATCATGTCAAATATAGCATAAAAGAACTCTCT AGGCTTTGTCAGTCATCTCAGTTCAGA---GGCAATGAAACTGAACTCATTACTGCAAATAAACGTGAACTTTCACAAAA CCTGTGTTATATACCATCACTTTCTCCCATCAGGTCATCTGTTAAAACTATATGTAAGAAAAAT---GTGTCAGAGGAAA AGCTTGAGGAACATTCAGTGTCCCCTGAAAGAGCACTGGGAAACAAGAGCGTCATTCAAAGTACAGTGAGCACAATTAGC CAAAATAACATTAGAGAAAGCACTTTTAAAGAAGTCGGCTCAAGCAGTATTAATGAAGTAGATTCCAGTACTAATGAAGT AGGCTCTAGTATTAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTGAAGCAGAGCTAGGCA GAAACAGAGGACCTAAATTAAATGCTATTCTCAGATTAGGTCTTATGCAACCTGAAGTCTATAAGCAAAGTCTT---CCA ATAAGTAATTGTAAACATCCGGAAATAAAAAGGCGAGGAGAAAATGAAGGAGTAGTTCAGCCTGTTAATGCAGATTTCTC TCCGTGTCCAATTTCAGATAACCTAGAACAA---CCTGTGGGAATTAGTTGTGCTTCTCAGGTTTGTTCTGAGACACCTG ATGACCTATTAAATGACAACGAAATAAAGGAAAATATCAGCTTTACTGAAAGTGGCATTAAGGAAAGATCTGCTATTTTT AGCAAAAGCGTCCAGAAAGGAGAATTCAGAAGGAGCCCTAGCCCTTTAGCCCGT---ACATGTTTGGCT---------CA AAGAGGGGCCAGGAAATTAGAGTCCTCAGAAGAGAACATGTCTAGTGAG >Pangolin TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATAAATGTAGA AAAGACTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCTGCAAAGCAGATGGGCTGAATGTAAAGAAA CATGTAACGAT---AGGCAGGCTCTCAGCACAGGGAAAAAGGTAGTTCTGAATGCTGATCCCCTGTGTGGGAGAAAAGAA CTGAATAAGCAGAAACCTTCATGCTCTGACAGTCCTAGAGTT---TCTCAAGAC---GTTCCTTGGATAACACTAAATAG TAGCATACRGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGAAATGTTAACTTCTGATGATCCATGTGATGGGAGGTCTG AATCAAATACTGAAGTAGCTGGTGCAGTAGAAGTTCCAAAT------GAAGTAGATGAAAATTGTGGTTCTTCAGAGAAA AAAGACTTAATGGCCAGTGATCCTCATGATGCTTTAATACGTGAAAGTAAAAGAGGCCACTCCAAACCAGTAGAGAGTAA T---ACTGAAGATAAAATATTTGGGAAAACCTATCGGAAGAAGGCAAGTCTCTCTCACTTGAGCCACGTAACTGAAAATC TAATTATTGGAGCATTTGCAGTAGAACCTCAGATAACACAA--------------------------------------- ---------------------GAGCGTCCCCTCAGAAATAGAGTAAAGCGTAAAAGGAGAACTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGTAGATTTGGAAGTTGTTCAAAAGACTCCTGAAAAGATAATTGAGGGAACCGACCAAATAG AGCAGAAT---------GCTCTTCTGATGAATAGAACAAATAACGGTCATAAGAATGAAACAAAAGGTGATTAT---GTT CAGAAAGAGAAAAATGCTAACCCAACAGAA------TCATTGAAAAAAGAACCTGCTTTCAGAACTAGAGCTGAACCTAT AACCAGCAATATAAGCAATATGGAGCTAGAATTAAATATCCATAGTTCAAAAGTACTTAAGAAGAATAGGCTGAGGAGGA AGTCTTCTACCAGGCACATTCATGCACTTGAACTAGTAGTCAATAGAAATCCAAGCCCCCCTAAACATACTGAACTACAA ATTGATAGTTGTTCTAGCAGTGAAGAGTTGATGAAA---------------AACCAAATACCAGTCAAACATNCCAAAAA GCTTCAACTCAAGGAAGATAGAGAACCTGCATCTAGAGCCAAGAAGAGTAACAAGCCAAATGAACAAATAAATAAAAGAT TTACCAGTGACACTTTTCCAGAACTAAATTTAACAAACATACCTGGTTTTTTTAGTAAATGTTCAAGTTCTAATAAACTT CAAGAGTTTGTTGACCCTAGCCTTCAAAGAGAAGAAATAGAAAATAAT---CTAGAAACAATTCTA------------AC CAAAGACCCCAAAGATGTGATATTACATAGAGGA------GGTTTGCAA---ACTGAAAGATGTGTAGAGAGTAACAGTA TTTCATTGGTACCTGATACTGATTACGGCACTCAGGATAGTATCTCATTACTGGAAGCTGACACACTAGGG---AAGACA AAA---ACAGCACCAAATCAATGTGCAAGTCTGTGTGCAGCAATTGAAAACCCCAAGGAACTTACCCATTGTTGT---GC TAAAGATATTAGAAATGACACAGAGAGCTTTAAGGATCTATTGAGACATGAAGATAAC---CACACTCAGGAGACAAGCA TAGGAACGGAAGAGAATAAACTTGATAAGCAGTACTTACAGAATACTTTCAGGGTTTCAAAGCATCAGTCATTTGCTCAG TTTTCAAATATGGGAAATCCAGAAAAAGAATGTGCAGCAGTCAGTGCCCACTCTGGGTCCTTAAGGAAACAAAGTCCAAA AGTCACTCTTGCATATGGACAAAAAGAAGAAAATGAGGGAAAGAAAGAGTCTGAAATCAAGCATGTTCAAACAATTCATA CAACTGCAGGCCCTCTTGTGGTTAGTCAGAAAGATGAGAAGCCAGGTGATTATGTAAAATTTGGCATAAAAGGAGTCTCT ACGCATTGTCAGTCATCTCAGTTCAGA---GGCAATAAAACTGAACTTATTTTTGCAAATAAACCTGGAATTTCACAATA CCCATATCATATATCATCAATTTCTCCCATCAGGTCATCTGTTAAAATAATATGTAAGGAAAAC---CTGTCAGAGGAAA AGTCTGTGGAACATTCGATGTCATTGGAAAAAGCAGTGGGAAACAAGAGCATCATTCAAAGTACTGTGAGCACAATTAGC CAAAATAACATTAAAGGAAACAATTTTAAAGATGGCAGCTCCAGCAGCATTAATGAAATAGGTTCCAGTACTAATGAAGT AGGCTCTAGTATTAATGAAGTAGGTTCCAGT---------------------GGTGAAAAAATTCAAGCAGAACTAGGTA GAAACAGAGGACCTAAATTAAGTGCTGTGCTCAGATTAGGTCTTATGCAACCTGAGGCCTATAAGCAAAATCTT---CTT ATAGGTAATCGTAAACACCCTGAAATTAAAAGACAAGGAGAAAAAGAAGGAGTAGTTCAGGTTGTTAATGCTGATTTCTC TCCATGTCTAATTTCAGATAACCTAGAACAA---CCTATGGGAAGTAGTCATGCTTCTCAGGTTTGTTCTGAGACACCTG AGGACATATTAAATGGTGATGAAATAAAGGAAAATATCGGCTTTGCTGAAAGTGGTATTAAGGAAAGATCTGCTGTTTCT AGCAAAAGTGTCCAGAAAGGAGAATTCAGAAAGAGCCCAAGCCCTGTAGTCCAT---ATGAGTTTGTCTCAGAGTCACCA AAGAAGAGCTGGGATAATAGAGTCTTCAGAAGAGAACATGTTTAGTGAG >Cat TGTGCCACAAATACTCGTGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGGCAGAATGAATGTAGA AAAGGCTGAATTCTGTAATGAAAGCAAACAGCCTGGCGTAGCAAGGAGCCAACAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCCAGCACAGAGAAAAAGGTAGTTCTGAATGCTGATCCCCTGTGTAGGAGAAAA--- CTGAGTAAGCAGAAATCTCCATGCTCTGACAGTCCTAGAGAT---TCCCAAGAT---GTACCTTGGATAACACTGAATAG TAGCATACAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGAAATGTTAACTTCTGATGACTCACATGATGAGGGATCTG AATCGAATCCTGGAGTAGCTGGTGCA---GAAGTTCCAAAT------GTAGTGGATGGATATTCTGGTTCTTCTGAGAAA ATAGACTTAATGGCCAGTGATCCTCATGATGCTTTGATATGTGAAAGTGAAAGAGTTCACACCAAACCAGTAGAGAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTTCCTAACTTGAGCCACACAAGTGAAGATC TCATTATAGGAGCATGTGCTATAGAACCTCAGATAACGCAA--------------------------------------- ---------------------GCCTATCCCCTCACAAATAAAACAAAGCGTAAAAGGAGATCTACCGCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGTAGATTTGGCCATTGTTCAAAAGACTCCTGAAAAGCTAATTGAGGGAACCGATCGAATAG GGCAAAAT---------GGCCATGTGATGAATAGAACAAATAATGGTCCTGAGAATGGGACAAAAGGTGATTAT---GTT CAGAAAGAGAAAAATGCTAAGCCAACAGAA------TCATTGGAAAAAGAATCTGCTTTTAGAACCAAAGCTGAACCAAT AAGCAGCAATATAAGTAATATGGAATCAGAATTAAATAGCCACAGTTCAAGGGCACCTAAGGAGAACAGGCTGAGGAGGA AGTCCTCTACCAGGCACATGCGTGCGCTGGAATTAGTAGTCAATAGAAATCCAAGCCCACCTGATCATACCGAACTACAG ATTGATAGTTGTTCTAGCAGTGAAGAGATGGTGAAAAGAAAA---AGTTCGGAACAAATGCTAGTCAGACACAGCAAAAC ACTTCAACTCGTGGAAAATAAAGAACCTGCACCTGGAGCCAAGAAGCGTAACAAGCCAAGTAAACAAATAAATAAAAGAC TTGCCAGTAACACTTTTCCAGAGCTAAATTTAACAAACATACCTGGGGTTTTTACTAACTGTTCAAGTTCTAATACACTT CAAGAGTTTGTCAACCCTGGCATTCAAAGAGAAGAACTAGAAGAGAGC---CGAGGAACGATTCACGTGTCTGATAGGAC CAGAGATCCCAAAGCGCTGGTATCGAGTGGAGGAAGA---AGTTTGCAA---ACTGAAAGATCTGTAGAGAGTACCAGTA TTTCATTGGTACCTGATGCCGATTATGGCACTCAGGATAGTATCTCATTACTGGAAGCTGACACCCTAGGG---AAGGCA AAA---ACAGCACCAAATCAACGTGTGAGTCTGTGTGCAGCAATTGAAAACCCCAAGGAAGCTATCCGTGGTTGT---TC CAAAGATACTAGAAATGGCACAGAGAGTTTTACAGATCCTCTGAGACGTGAAGATANC---CATACTCAGGAGACAAGTA TAGAAATGGAAGAGAATGAACTTGATACGCAGTGGTTATACAATACGTTCAAGGGTTCAAAACGTCAGTCATTTGCTCTG TTTTCAAATCCAGGAAACCCAGAAAAGGAATGTGCTACAGCCTGGGCCCGTTCCACGTCCTTAAGGAAACAAAGTCCAAA AGTCGCTCTTGAATATGAACAAAAAGAAGAAAATCAGGGAAAGAATCAGTCTGAAATCAAGCATGTGCAGGCAGTCCGTG CAACTGCAGGCTTTTCTGCAGTCAGTCAGAAAGTGGAGAAGCCAGGTGATTATGCCAAATGTAGCATAAAAGGAGTCCCT GGGCTCTGTCAGTCATCTCAGTTCAGA---GGCAATGAAACTGAACTCTTTATTGCAAATAACCATGACATTTCAAAAAA CCCTTATCATATACCACCACTTTCTCCCATCAGATCATCTGTTAATGCTGTATGTAAGAAAAAC---CTGTCAGAGGAAA AGTTTGAGCAGCGTTCAATGTCACCTGAAAGAGCAGTGGGAAATGAGAGCGTCATTCAAAGTACAGTGAACACAATTAGC CAAAATAACATTAGAGAAAACACTTTTAAAGAAGTTAGCTCAAGCAGTGTTAATGAAGTAGGTTCCAGTGCTAATGAAGT AGGCTCTAGCATTAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTCAAACAGAACTGGGTA GAAACCGAGGACCTAAGTTAAGTGCTATGCTCAGGTTAGGTCTTATGCAACCTGAAGTCTATGAGCAAAGTCTT---CCT ATAAGTAATTGTAAATGTCCAGAAATGAAAAGGCAAGGAGAAAATGAAGGAGTAGTTCAGTCTGTTAATGCAGATTTTTC TCCATGTCTAATTTCCGATAATGTAGAACAA---CCTATGGAAAGTAGCCGTGCTTCTCAGGTTTGTTCTGAGACACCCA ATGACCTATTAAATGGTGATGAAATAAAGGGAAAAATCAGCTTTGCTGAAAGT---GCTAAGGAAAGATCTGCTGTTTTT GGCAAGAGTGTCCAGAAAGGAGAATTCAGAAGGAGCCCTAGCCCTTTAGACCAT---ACACATCTGGCTCAGGGTCACCA AACAGAGACCAGGAAGTTAGAGTCCTCAGAAGAGAACGTGTCTAGTGAG >Dog TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAACACAGAATGAATGTAGA AAAGGCTGAAATCTGTAATAACAGCAAACAGCCTGGCTTAGCAAGGAGCCAACAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGATTCCCAGCACAGAGAAAAAGGTAGTTGTGAATGCTGATCTCCTGTGTGGGAGAAAAGAA CTGAATAAACAGAAACCTCCACACTCTGATAGTCCTAGAGAT---TCCCAAGAT---GTTCCTTGGATAACACTGAATAG TAGCATACGGAAAGTTAATGAGTGGTTTTCCAGAAGTGACGAAATATTAACTTCTGATGATTCACATGACAGAGGATCTG AATTGAATACTGAAGTAGGTGGTGCAGTAGAAGTTCCAAAT------GAAGTGGGTGAATATTCTGGTTCTTCTGAGAAA ATAGACTTAATGGCCAGTGATCCTCAGGATGCTTTCATATGTGAAAGTGAAAGAGTCCACACCAAGCCAGTAGGAGGTAA T---ATCGAAGATAAAATATTTGGAAAAACCTATCGGAGGAAGGCAAGCCTCCCTAAGGTGAGCCACACAACTGAAGTTC TAACTATAGGAGCGTGTGCTATAGAACCTCAGACAATGCAA--------------------------------------- ---------------------ACCCATCCCTTCATGAATAAAGCAGAGCATAAAAGGAGAACTACATCTAGCCTTCATCC TGAGGATTTTATCAAGAAAGTAGAGTTAGGCATTGTTCCAAAGACTCCTGAAAAGCTAATTGAGGGAATCAACCAAATCA AGCGAGAT---------GGTCATGTGATAAATATTACAAATAATGGTCCTGAGAATGAAACAGAAGGTGATTAT---GTT CAGAAAGAGAAAAATGCTAACCCAACAGAA------TCATTGGAAAAAGAATCTGCTTTTAGAACCAAAACTGAACCAAT GAGCAGCAGGATAAGCAATATGGAACTGGAATTAAATAGCTCCAGTTCAAAAGCACCTAAGAAGAACAGGCTGAGGAGGA AGTCCTCTGCCAGGCACACTTGTGCCCTTGAATTCGTAGTCAATAGAAATCTAAACCCACCTGATCATAGTGAACTACAG ATTGAAAGTTGTTCTAGCAGTGAAGAG---ATGAAGAAACAG---CATCTGGACCAAGTACCAGTCAGACACAACAAAAC ACTTCAGCTCATGCAAGATAAAGAACCTGCAGGTAGAGCTAAGAAAAGTAGTAAGCCAGGAGAACAAATAAATAAGAGAC TCGCCAGCCATGCTTTTCCAGAGCTAACTTTAACAAATGTATCTGGTTTTTTTGCTAACTATTCAAGTTCTAGTAAGCCT CAAGAGTGCATCAACCCTGGCCTTCGAAGAGAAGAAATAGAAGAGAGC---CGAAGAATGACTCAAGTGTCTGATAGTAC CAGAGATCCCAAAGAGCTGGTATTGAGTGGAGGAAGA---GGTTTGCAA---ACTGAGAGATCTGTAGAGAGTACCAGTA TTTCATTGGTACTTGATACTGATTATGGTACACAGGACAGTATCTCATTACTGGAAGCTGACACCCTGAGG---AAGGCA AAA---ACAGTATCAAATCAACAGGCGAATCTGTGTGCAACAATTGAGAACCCCAAGGAACCTATCCATGGTTGT---TC TAAGGACACTAGAAATGACACAGAGGGTTTTGTAGTTCCATTGACGTGCAAAGATAAC---CACACTCAAGAGACAAGCA TAGAAATGGAAGAGAGTGAACTTGACACGCAGTGCTTACGCAATATGTTCAAGGTTTCAAAGCGTCAGTCATTTGCTCTG TTTTCATATCCAAGAGATCCGGAAGAGGACTGTGTAACAGTCTGTCCCCGCTCTGGGGCCTTTGGAAAACAAGGTCCAAA AGTCACTCTAGAATGTGGACAGAAAGAAGAAAGTCAGGGAAAGAAAGAGTCTGAAATCAGACATGTGCAGGCAGTTCATA CAAATGCAGGCTTTTCTGCAGTTAGTCAGAAAGCTAAGAAGCCAGGCGATTTTGCCAAATGTAGCATAAAGGGAGTCTCT CGGCTTTGTCTGTCATCTCAGTTCAAA---GGCAAGGAAACTGAACTCCTTATTGCAAATTACCATGGAATTTCCCAAAA CCCTTATCATATACCACCACTTTCTCCCATCAGATCATGTGTTAAAACTCTATGTCAGGAAAAC---CTGTCAGAGGAAA AGTTTGAGCAACATTCAATGTCACCCGAAAGAGCAGTGGGAAATGAGAGAGTCATTCAAAGTACAGTGAGCACAATTAGC CAAAATAACATTAGAGAATGTGCTTCTAAAGAAGTCGGCTCAAGCAGTGTTAATGAAGTAGTTTCCAGTACTAATGAAGT AGGCTCTAGTGTTAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTCAAGCAGAACTAGGTA GAAACCGAGGACCTAAATTAAATGCTATGCTCAGATTAGGTCTTATGCAACCTGAAGTCTGTAAGCAAAGCCTT---TCT TTAAGTAATTGTAAACATCCAGAAATGAAATGGCAAGGACAAAGTGAAGGAGCAGTTCTGTCTGTTAGTGCAGATTTCTC TCCATGTCTGATTTCAGATAACCCAGAACAA---CCTATGGGAAGTAGTCGGTCTTCTCAGGTTTGTTCTGAGACACCTG ATGACCTATTAAATGGTGACAAAATAAAGGGAAAAGTCAGCTTTGCTGAAAGTGACATTAAGGAAAAATCTGCTGTGTTT AGCAAAAGTGTCCAGAGTGGAGAGTTCAGCAGAAGCCCTAGCCCTTCAGACCAT---ACACGTTTGGCCCAGGGTTACCA GAGAGGGACCAAGAAATTAGAGTCCTCAGAAGAGAACATGTCTAGTGAG >Llama TGTGGCACAGATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAGGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGTCTTAGCAAGGAGCCAACAGAGCAGATGGGCTGAAAGTAAGGACA CATGTAATGAT---AGGCAGACTCCCAGCACAGAGAAAAAGGTGGCTCTGAATGCCGATCGCTTATATGGGAGCGAAGAA CTGAATAAGCAGAAACCTGCATGCTCTGACAGTCCTAGAGAT---TCCCAAGAT---GTTCCTTGGATAACACTGAATAG TAGCATACAGAAAGTGAATGAGTGGTTTTCCAGAAGCGACGAAATGTTACCTTCTGATGACTCACATGAAGTGGGGCCTG AATCAAATACTGAAGTAGCTGGTGCAGTGGAAGTTCCAAAT------GAAGTAGATGGCTATTCAGGCTCTTCAGAGAAA ATAGACTTAATGGCCAGTGATCCTCATGGTGCTTTAAAATGTGAAAATGAAAAAGTCCACGCCAAACCAGTAGGGAGTAA C---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCTAACTTGACCCACAGAGCTGAAGATC TAATTCTAGGAGCATCTGTTCTAGAGCCTCAGATAACACAA--------------------------------------- ---------------------GAGCGCCCCTTCACAAATAAACTAAAGCGTAAAAGGAGAACTCTACCAGGTCTTCATCC TGAGGATTTTATCAAGAAAGTCGATTTGGCCGTTGTTCAAAAGTCTCCTGAAAAGATAATTGAGCGAACAGACCAAACAG AGCAGAAT---------GGTCATGGGATGAATATTACTAGTAATGGTCATGAGAATGAAACAAACGACGATTAT---GTT CAGAAAGAGAAAAATGCTAACCCAACAGAA------TCATTGGAAAAAGAATCTGCTTTCAAAACTAAGGCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTAGAATTGAATACCCATAGTTCAAAAGCACCTAAG---AATAGGCCGAGGAGGA AGTCCTCTACCAGGCAGATTCATGCACTTGAACTAATAGTCAGTAGAAACCCAAGCCCACCTAATCACACTGAACTACAG ATTGAGAGTTGTTCCAGCAGTGAAGAG---ATGAAGGAAAAA---CATTCTGACCAAATGCCAGTCAGGCACCGCAAAAA GCTTCAGCTCACGGGAGATAAAGAACCTACGACTGGAACCAAGAAGAGTAACAAGCCACATCAACAAATAAATAAAAGAC TTGTCGGTAACACTTTTCCAGAACTAAATTTAACAAACACACCTGGTTTTTTTACTAAGTGTTCAAGTTCTAATAAACTT CAAGAGTTTGCCAATCCTAGCCTTCAAAGAGAA---------GAGAAC---CCAGGAGCAATTCAAGTATCGAACAGTAC CAAAGACCCCAAAGTTCTGATATTAAGTGGAGGGAGA---GGTTTACAA---ATTGAAAGATCTGTAGAGAATACCAGTA TTTCCTTGGTACCTGAAACTGATTATGACACTCAGGACAGTGTCTCATTACTGGAAGCTGACACCCTAGGG---AAGGCA AAA---ACAGCACCAAATCAATGTGTGAGTCTCTGTGCAGCAACTGAAAACCCCAAGGAACTTATCCATAGTTGT---TC TAAAGATACTAGAAATGGCACAGCAGGCTTTAAGGATCCATTGGGATGTGATGTTAAT---CACACTCAGGAGGCAAGCA TGGAAGTGGAAGAGAGTGAACTTGATACTCAGTATTTGCAGAATACGTTCAAGGTTTCAAAGCGTCAGACATTTGCTCTG TTTTCAAATCCAGGAGATTCAGAAAAGGAATGTGCAACGATCTATGCCCACTCTGGGCCCTTAAGGGAACAAAGTCCAAA AATCACTCTTGAATGTGGACAAAAAGAAGAAAATCAGAGAAAGAGCAAGTCTGAAATCAAGCATATGCAGGCAGTTCATA CAACTTTGAACTTTCCTGTGGTTGGTCAAAAAGATAAG---CCGAGTGATTATGCCAAATATAGCCCAAAAGGAATATCT AGGCTTTGTTGGCCATCACAGCTCAGA---GGCAATGAATCTGAGTTCATTATTGCAAATAAACATGGGATTTTACAAAA CCCATATCTTATAACATCACTTTCTCCTAACAGGTCATCTGTTAAAACTATGTGTAAGAAAAAC---CCGTCCGAGGAAA AGCTTGAGAAATGTGTCATATCACCTAAAAGAGTGATGGGAAACGAGAGCACCATTCAAAGTATAGTGAGTGCAATGAGC CAAAATAACATTAGAGAAAGCACTTTTAAAGAAGTCAGCTCAAGCAGTGTCAATGAAGTAGGTTCCAGTACTAATGAAGT AGGTTCTAGTATTAATGAAGTAGGTTCCAGT---------------------GGCGAAAACATTCAAGCAGAACTAGGTA GAAACATGGGACCTAAATTAAATGCTATGCTCAGATTAGGTCTTTTGCAACCTGAAGTCTGTAAGCAAAGTCTT---CCT GTAAGTAATTGTAAACAACCTGAAATAAAAAGGCAAGGAGAAAATGAAGGCATCTTTCAGGCTGTTAATACCGACTTCTC TCCATGTCTAATTTCAGATAACCTAGAACAA---CCTATGGGAAGCAGTCATGCTTCTCAGGTTTGTTCTGAGACACCTG ATGACCTGTTATATGATGACGAAATAAAGGAAAATACCAGCTTTGCTGAAAGTGACATTAAGGAAAGATCTGCTGTTTTT AGCAAAAGTGTCCAAAAA---GAATTCAGAAGGAGCCCTAGCCCTTTAGTGCAT---ACGCATTTGGCTCAGGGTCACCA AAGAGGGGCTAGGAAATTAGAGTCCTCAGAAGAGAATGTGTCTAGTGAG >Pig TGTGGCACAGATACTCATGCCAGCTCGTTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTTTGTAATAAAAGCAAGCAGCCTGTCTTAGCAAAGAGCCAACAGAGCAGATGGGCTGAAAGTAAGGGCA CATGTAATGAT---AGGCAGACTCCTAACACAGAGAAAAAGGTAGTTCTGAATACTGATCTCCTGTATGGGAGAAACGAA CTGAATAAGCAGAAACCTGCGTGCTCTGACAGTCCTAGAGAT---TCCCAAGAT---GTTCCTTGGATAACATTGAATAG TAGCATACAGAAAGTTAATGAGTGGTTTTCTAGAAGCGATGAAATGTTAACTTCTGACGACTCACAGGACAGGAGGTCTG AATCAAATACTGGGGTAGCTGGTGCAGCAGAGGTTCCAAAT------GAAGCAGATGGACATTTGGGTTCTTCAGAGAAA ATAGACTTAATGGCCAGTGACCCTCATGGTGCTTTAATACGTGAACGTGAAAGAGGGCACTCCAAACCAGCAGAGAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCTAACTTGAGCCACGTAATTGAAGATC TAATTTTAGGAGCATCTGCTGTAGAGCCTCAAATAACACAA--------------------------------------- ---------------------GAGCGCCCCCTCACAAATAAACTAAAGCGGAAAAGGAGAGGTACATCAGGCCTTGATCC CGAGGATTTTATCAAGAGAGCCGATTCGGCAGTTGTTCCAAAAACTCCTGAAAAGACAATTGAGGGAACTGATGAGACAG AGCAGAAT---------GGTCAGGGGATGAATATTACCAGTAAAGGTCATGAGAATGAAACAAAAAGTGGTAAT---GTT CAGAAAGAGAAAAATGTTAACCCAACTGCA------TCGTTGGGAAAAGAACCTGCTTTCAGAGCTAGGGCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTAGAATTGAATATCCATGGTTCGAAAGCACCAAAG---AACAGGCTGAGGAGGA AGTCCTCTACCAGGCAGATCCATGCACTTGAACTAGTAGTCAATAGAAACCCAAGCCCACCTAGTCATACTGAGTTACAA ATTGATAGTTGTTCTAGCAGTGAAGAG---ATGAAGAAGAGA---AATTCCGACCAAGTGCCAGTCAGGCACAGCAAAAA GCTTCACCTCAGGGGAGATAAAGAACCTACAACTGGAGCCAAGAAGAATAATAGGCCACATGAACAAGTAAATAAAAGAC CTATCAGTGATGCTTTTCCAGAACTAAATTTAACAAATGTACCTGTTTCTATTACTAACTGTTCAAATTCTAATAAGCTT CAAGAATCTGTCAGTCCTAACCTTCAAAGAGAA---------GAGAAC---CTAGGGACAATTCAAGTGTCGAATAGTAA CAAAGACCCCAAAGATGTGATGTTAAGTGGAGGAAAA---GGTTTTCAA---ATTGAAAGATCTGTAGAGAATACCAGTA TTTCCCTGGTACCTGATACTGATTATGGCACTCAGGACAGTATCTCATTACTGGAAACTGACACCCTAGGA---AAGGCA AAA---ACAACACCCAATCAACATGTGAGGCTGTGTGCAGCAACTGAAAACCCCAAAGAACTTAGCCTTGGTTGT---TC TAAAGGTGTTAGAAACGACACAGGGGACTTTAAGGATCCCCTGGCTCATGATGTTAAC---CACACTCAGGAAGCAAGCA TAGAAGTGGAAGAGAATGAACTTGATACACAGTATTTGCAGAGTATGTTCAAGGTTTCAAAGCGTCAGACATTTGCTCTG TTTTCAAATCCAGCAAATCCAGAAAAGGAATGTACAACCGTCCATGCCCACTCCAAGTCCTTAAGAGAACAAAGTCCAAA AGTCACTCATGAAGGTGGACAAAAAGATGAAAATCAGGGAAAGAGTGAGTCTAAAGTCAAGCATGGGCAGTCAGTTCATA CAACTGTGGACTTTCTAGTGGTTGGTCAAAAGGATAAGAAGCCGAGTGATTTTGCCAAATGTGGTGCAAAAGGAGTAACT GGGCTTTATCAGACATCACAGTTCAGA---GGCCACAAAACTGAGTTCATTAATGCAAATAAACCTGGGATTTCACAAAA CCCATATGTCATACCATCCCTTTCTCCCATCAGGTCGTCTGTTAAAACTATATGTAAGAAAAAC---CTGTCAGAGGAAA AGTTTGAGGAACCTAAAATGTCACCCGAAAGAACAATGGGAAACGAGAGCATCATTCCAAATACAGAGAGCACAGTTAGC CAAAATAACATTCAAGAGAGAACTTTTAAAGAAGGCAGCTCAGGCAGTCCTAATGAAGTCGGGTCCAGTACCAACGAAGT AGGCTCTAGTATTAATGAAGTAGGTTCCAGC---------------------GGTGAAAACGTTCGAGCAGAACCAGGTA GAAACAGAGGACCTAAATTAAGTGCAATGCTCAGATTAGGTCTCATGCAACCCGAAGTTTATAAGCAAAGTCTT---CCT GTAAGTAATTGTAACCACACAGAAATAAAAAGGCAAGGAGAAAATGAAGGCATATTTCAGGCTGTTAATGCAGATTTCTC CCCATATCTAATTTCAGATAACCCCGAACAA---CCTATGGGAAGTAGTCATGCTTCTCAGATTTGTTCTGAGACACCTG ATGACCTGTTAAATGATGACAAAATAAAGGAAAATCTCAACTTTGCTGAAAGTGACGTTAAGGAAAGATCTGCTGTTTTT AGCAAAAGTGCCCAAGAAGGGGAATTTAAAAGGAGCCCTAGCCCTTTAGCCCAC---AGACGTTTGGCTCAGGGTCACCA AAGATGGGCTAGGAAATTAGAGTCTTCAGAAGAGAGTGGGTCTAGTGAG >Cow TGTGGCACAGATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTGCTCACTGAAAACAGACTGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGTCTTAGTAAAGAGCCAGCAGAGCAGATGGGCTGAAAGTAAGGGCA CATGTAAGGAT---AGGCAGATTCCCAGCACTGAGAAAAAGATAGTTCTGAATACTGATCCCCTGTACAGAAGAAAAGAA CTGCGTAAGCAGAAACCTGCATGCCCTGACAGTCCTGGAGAT---TCCCAAGAT---GTTCCTTGGGTAACCCTGAATAA TAGCATACAGAAAGTTAATGACTGGTTTTCCAGAAGTGATGAAATATTAACTTCTGATGACTCGTGCGATGGGGGGTYTG AATCAAATAATGAAGTAGCTGGTGCAGTGGAAATTCCAAAT------AAAGTAGATGGATATTCAGGTTCTTCAGAGAAA ATCAACTTAATGGCCAGTGATCCTCATGGTACTTTAATACAC------GAAAGAGTCCACTCCAAACCCGTAGAGAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGTCAAGTCTCCCTAACTTCAGCCACATAGCTGAAGATC TAATTCTAGGCGCATTTACTGTAGAACCTCAGATAACACAA--------------------------------------- ---------------------GAGCAGCCCCTCACAAATAAACTAAAATGTAAAAGGAGAGGTACATCAGGCCTTCAGCC TGAGGATTTTATCAAGAAAGTCGATTTGACAATTGTTCCAAAGACTCCTGAAAAGATGACGGAGGGAACTGACCAAACAG AGCAGAAA---------TGTCATGGGATGAATATTACTAGTGATGGTCATGAGAATAAAACAAAACGTGATTAT---GTT CAGAAAGAGCAAAACGCTAACCCAGCAGAA------TCATTGGAAAAAGAATCTGTTTTCAGAACTGAGGCTGAACCTAT AAGCATCAGTATAAGCAATATGGAACTAGAATTGAATATCCACCGTTCAAAAGCACCTAAG---AATAGGCTGAAGAGAA AGTCCTCTACCAGGAAAATTCCTGAACTTGAACTAGTAGTCAGTAGAAACCCAAGTCTACCTAATCATACTGAGCTACCA ATTGATAGCAGTTCTAGCAATGAAGAG---ATGAAGAAAAAA---CATTCTAGCCAAATGCCAGTCAGGCAGAGCCAAAA GCTTCAACTCATTGGAGATAAAGAACTTACTGCTGGAGCC---AAGAATAACAAAACATATGAACAAATAAATAAAAGAC TTGCTAGTGATGCTTTTCCAGAACTAAAGTTAACAAACACACCTGGTTATTTTACTAACTGTTCTAGT------AAACCT GAAGAGTTTGTTCATCCTAGCCTTCAAAGAGAG---------GAGAAC---CTAGGAACAATTCAAGTGTCGAATAGTAC CAAAGACCCCAAAGATCTGATATTAAGAGAAGGAAAA---GCTTTGCAA---ATTGAAAGATCTGTAGAGAGTACCAATA TTTCCTTGGTTCCTGATACTGATTATAGCACTCAGGATAGTATCTCATTACTAGAAGCTAAAACCCCAGAA---AAGGCA AAG---ACTGCACCAAATCCATGTGTGAGTCTGTGTACAGCAACCAAAAACCTCAAGGAACTTATCCATAGGGAT---TT TAAAGATACCAAAAACAACACAGAGGGCTTTCAGGATCTACTGGGACATGACATTAACTACGTCATTCAGGAGACAAGCA GAGAAATGGAAGACAGTGAACTTGATACACAGTATTTGCAGAATACATTCAAGGCTTCAAAGCGTCAGACATTTGCTCTG TTTTCCAATCCAGGAAATCCACAAAAGGAATGTGCCACAGTCTTTGCCCACTCGGGGTCCTTAAGGGATCAAAGTCCAAG AGACCCCCTCAAATGCAGACAAAAAGAAGACAGTCAGGGAAAGAGTGAGTCTAAAAGCCAGCACGTGCAGGCCATTTGTA CAACAGTGCACTTTCCTGTGGCTGATCAGCAAGATAGGACGCCAGGTGACGATGCCAAATGTAGCGCAAAAGAAGTAACT AGGGTTTGTCAGTCATCACAGTTGAGA---GGCCACAAAACTGAACTTGTTTTTGCAAATAAACAAGGGGTTTCAGAAAA ACCAAATCTTATACCATCACTTTCTCCCATCAAGTCATCTGTTAAAACCATATGTAAGAAAAGC---CCATCAGAG---A AGTTTGAGGAACCTGTAACGTCACCTGAAAAAACATTGGGGAGTGAGAGCATCATTCAAAGTGCAGTGAGCACAATCAGC CAAAATAACATTCAAGAAAGCACTTTTAAAGAAGTCAGCTCAAACAGTGTAAATGAAGTAGGTTCCAGTACTAATGAAGT AGGCTCTAGTGTTAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTCAAGCAGAACCAGGTA GAAACAGAGAACCTAAATTAAGAGCTTTACTCGGATTAGGTCTTACGCAACCTGAAGTCTATAAGCAAAGTCTT---CCT GTAAGTAACTGTCACCATCCTGAAATAAAAAGGCAAGGAGAAAATGAGGACATGCCTCAGGCTGTTAAGGCAGATTTCTC CCCATGTCTAATTTCAGATAACCTCGAACAA---CCTACGGGAAGCCGTCATGCTTCTCAGGTTTGTTCTGAGACACCTG ACAACTTGTTAAATGATGATGAAATAAAAGAAAATAGCCACTTTGCTGAAAGTGACATTAAGGAAAGATCTGCTGTTTTT AGTGAAAGTGTCCAAAAAGGAGAATTCAGAGGGAGCCCTGGCCCTTTCACCCAT---ACACATTTGGCTCAGGGTCACCA AAGAGGGGCTGGCAAACTAGAG---TCAGAAGAGACTGTGTCTAGTGAG >Hippo TGTGGCACAGATACTCGTGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGCAGA AAAGGCTGAATTCTGTAATAAAAGCNAACAGCCTCTCTTAGCAAAGAGCCAACAGAGCAGATGGGCTGAAAGTAAGGACA CATGTAATGAT---AGACAGACTCCCAGCACAGAGAAAAAGGTAGTTCTGAACGCTGATCCCCTATACGGGAGAAAAGAA CTGAATAAGCAGAAACGTGCATGCTCTGACGGCCCTAGCGAT---TCCCAAGAT---GTTCCTTGGATAACACTGAATAG TAGCATACAGAAAGTTAATGAATGGTTTTCCAGGAGTGGCGAGATGTTAACTTCTGACGACTTATGTGTTAAGGGGTGTG AATCAAATACTGAAGTAGCTGGTGCAGCGGAAGTTCCAAAT------GAAATTGATGGGTGTTTGGGTTCTTCAGAGAAA ATAGATTTAATGGCCCGTGACCCTCGTGGTGCCTTAATACGTGAAAGTGAAAGAGTCCACGCCAAACCAGTAGAGAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCTAACTTGAGCCACATAGCTGAAGATC TAATTAAAGGAGCATCTGCTGTAGGACCTCAGATAACACAA--------------------------------------- ---------------------GAGCGCCCCCTCACAAATAAACTAAAGCGTAAAAGGAGGCGGACATCGGGCCTTCATCC TGAGGATTTTATCAAGAAAGTCGATGCGGCAGTTGTTCCAAAGACTCCTGAAAAGATAATTGAGGGAACTGATCAAACAG AGCAGAAT------------------------------------GGTCATGAGAATGAAATGAAAGGTGATTAT---GTT CAGAAAGAAAAAAATGCTAACCCAACAGAA------TCTTTGGAAAAAGAATCTGCTTTCAGAACTAAGGCTGAACCTAT AAGCATCAGTATAAGCAATATGGAACTAGAATTGAATATCCACAGTTCAAAAGCACCTAAG---AGTACGCTGAGAAGGA AGTCCTCTACCAGGCAGATTCATGCACTTGAACTAGTAGTCAGTAGAAACCCGAGCCCACCTAATCGTACTGAACTACAA ATCGATAGTTGTTCTAGCAGTGAAGAG---ATGAAGAAAAAA---CATTCCTGCCAAATGCCAGTCAGGCACAGCAAAAA GCTTCAATTCATGGGATATAAAGAACCCGCAACTGGAGTCAGGAAGAGTAATAAACCACACGAACAAATAAATAAAACAC TTGCCAGTGGTGCTTTTCCAGAACTAAATGTAACAAACATACCTGGTTTTTTTACTAACTGTTCTAGTTCTAGTAAACTT CAAGAGGTTGTTAATCCTGGCCTTCCAAGAGAG---------GAGAAC---CTAGGAACAATTCAAGTGTCAAATAGTAC CAAAGACCCCAAAAATCTGATATTAAGTAGAGGAAAA---GGTTTGCAA---ATTGAAAGATCTATAGAGAGCACCAGTA TTTCCTTGGTACCTGATACTGATTATGGCACTCAGGACAGTATCTCATTACTGGAAGCTGACACCCTAGGG---AAGGCA AAG---ACAGCAACAAATCAACGTGTGGGTCTGTGTGCAGCAACTGAAAACCCCAAGGAACTTATCCATGGTTAT---TC CAAAGATACTAGAAACGACATGGACGGCGTCCAGCATCCATTGGGACAGGATGTTAAC---CACACTCAGGATGCAAGCA TAGAAGTGGAAGACAGTGAACTTGATACACAGTATTTGCAGAATACATTCAGGGTTTCAAAGCGTCAGACATTTGCCCTG TTTTCAAATCCAGGAAATCCAGGAAAGGAACGTGCAACAGTCTGTGCTCATTCCGGGTCCTTAAGGGAACAAAGTCCAAG AGTCCCTCTTGAATGCGGACAAAAAGAAGAAAATCAGGGCAAGAGTGAATCTAAA---------ATGCAGGCAATTTATA CAACTGTGGACTTTGCTGTGGCTGGTCAAAATGATAGGAAGCCGAGTGATTACACCAAATGTAGCACTAAAGGAGTAACT AGGCTTTGTCCCTCATCACAGTTTGGA---AGCAACAAAACTGAGCACATTATTGCAAATAAATATGGAATTTCACAAAA CCCATATGTTATACCATCACTTTCTCCCATCAGGTCATCTGTTAAAACTATACGGAAGAAAAAC---CTGTCAGAGGAAA AGTTTGAGGAACCTGTAGTGTCAGCTGAAAGAGCAATGGCAAATGAGAGCATCCTTCAAAGTACAGTGAACACAATTAGC CAAAATAACATTCGAGAAAACACTTTTAAAGAAGTCAGTTCAAGCAGTATTAATGAAGTAGTTTCCAGTACTAATGAAGT AGGCTCTAGTATCAGTGAAGTAGGTTCTAGT---------------------GGTGGAAACATTCAAGCAGAACTAGACA GAAAGAGAGGACCTAAACTAAGTGCTTTGCTTAGATTAGGTCTTATGCAACCTGAAGTATATAAGCAAAGTCTT---CCT GTAAGTAATTGTCAACATCCTGAAATAAAAAGGCAAGGAGAAAATGAAGGCATACTTCAGGCTGTTAATGCAGATTTCTC CCCGTGTCTAATTTCAGATAACCTAGAACAA---CCTATGGGAAGCAGTCATGCTTCTCAGGTTTGTTCTGAAACACCTG ATGATTTGTTAAATGATGACGGAATAAAGGAAAATAGCAACTTTGCTGAAAGTGACATTAAGGAAAGATCTGCTGTTTTT AGCAAAAATGTCCAAAAAGGAGAATTCAGAAGGAGCCCTGGCCCTTTAGCCCAT---ACACGTTTGGCTCAGGGTCACCA AAGAAGGGCTGGGAAATTGGAGTCCTCAGAAGA---------------- >SpermWhale TGTGGCACAGATACTCATGCCAGCTCATTACAGCATGAAAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGTCTTAGCAAAGAGCCAACAGAGCAGATGGGCTGAAAGTAAGGACA CATGTAATGAT---AGGCAGACTCCCAGTACAGAGAAAAAGGTAGTTCTGAATGCTGATCCCCTATATGGGAGAAAAGAA CTGAATAAGCAGAAATCTGCATGCTCTGACAGTCCTAGAGAT---TCCCAAGAG---TTTCCTTGGATAGCAGTGAATAG TAGCATACAGAAAGTTAATGAATGGTTTTCCAGAAGTGATGAAATGTTAACTTCTAACGACTTACGTGATGGGGGATTTG AATCAAACCCTGAAGTAGCTCGTGCAGTGGAAGTTCCACAG------GAAGTTGATGGATATTTGGGTTCTTCAGAGAAA ATAGACTTAATGGCCAGTGATCCTCATGGTGCTTTAATACGTGAAAGTGAAAGAGTCCACTCCAAACCAGTAGAGAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCTAACTTGAGCCACGTAGCTGAAAATC TAATTATAGGAGCATCTACTGTAGGACCTCAGATTACACAA--------------------------------------- ---------------------GAGCGCCCCCTCACAAATAAACTAAAGCGTAAAAGGAGAAGTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGTCGATTTGGCAGTTATTCCAAAGACTCCTGAAAAAATAATTGAGGGAACTGACCAAACAG AGCAGAAT---------GGTCATGGGGTGAATATTACTAGTAATGGTCATGAGACTGAAATGAAAGGTGATTGT---GTT CAGAAAGAGAAAAATGCTAACCTAACAGAA------TCATTGGAAAAAGAATCTGCTTTCAGAACTAAGGCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTAGAATTGAATATCCATAGTTCAAAAGCACCTAAA---AATAGGCTGGGGNGGA TGTCCTCTTCCAGGAAGATTCATGCACTTGAACTAGTAGTCAGTAGAAACCCAAGCCCACCTAATCATACTGAACTACAA ATTGATAGTTGTTCTAGCACTGAAGAG---ATGAAGAAAAAA---CATTCCAGCCAAATGCCAGTCAGGTGCGGCAAAAA GCTTCAATTCATTGGAGATAAAGAACCTACAACTGGAGCCAAGAAGAGTAACAAGCCACATGAACAAATAAATAAAAGAC TTGACAGTGACACTTATCCAGAACTAAATTTAACAAACATACCTGTTTTTTTTACTCACTGTTCTAGTTCTAATAAACTT CAAGAGTTTGTTAATCCTAGCCTTCAAAGAGAG---------GAGAAC---CTAGGAACAATTCAAGTGTCGAATAGTAC TGAAGACCCCAAAGATCTGACATTAAGTGGAGGAAAA---GGTTTGCAA---ATTGAAAGATCTGTAGAGAGTTCCAGTA TTTCCTTGGTACCTGATACTGATTATGGCACTCAGGATAGTATCTCATTACTGGAAGCTGACACCCTAGGG---AAGGCA AAG---ACAGCACCAAATCAACATGTGAGTCTGTGTGCAGCAATTGAAAGCCCCAAGGAACTTATCCACGGTTGT---TC TAAAGATATTAGAAACGACACAGAGGACTTTAAGGATCCACTGGGACATCACGTTAAC---CACATTCAGGAGGCGAGCA CAGNNNNNNNNNNNNNNNNACTTGATACTCAGTTTTTGCAGAATATGTTCAAGGTTTCAAAGCGTCAGACGTTTGCTCTG TTTTCAAATCCAGAAAATCCAGAAAAGGAATGTGCAACAGTCTGTGCCCACTCTGGGTCCTTAAGAGAACAAAGTCCAAG AGTCCCTCTTGAATGCAGACAAAAAGAAGAAAATCAGGGAAAGAGTGAGTCTAAAATCAAGCATGTGTGGGCAATTAATA CAACTGTGGACTTCCCTGTTGCTGGTCAAAAAGATAAG---CCGAGCGATCATGCCAAACGTAGCCCCAAAAGAGTAACT AGGCTTTGTCAGTCATCACAGTTCAGA---AGCAACAAAACTGAGCTCATTATTGCAAATAAACATGGGATTTCACAAAA CCCATATCTTATACCATCACTTTCTCCCATCAGGTCATCTGTTAAAACTATATGTAAGAAAAAC---CTGTCAGAGGAAA AGTTTGCGGAACCTGTAATGTCACCTGAAAGAGCAATGGAAAACGAGAGCATCATTCAAAGTACAGTGAGCACAATCAGC CAAAATAACATTCGAGAAAGCACTTTTAAAGAAGTCAGCTCAAGCAGTACTAATGAAGTAGGTTCCAGTACCAATGAAGT AGGCTCTAGTATTAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTCAAGCAAAACTAGATA GAAACAGAGGACCTAAATTAAGTGCTTTGCTCAGATTAGGTCTCATGCAACCCGAAGTCTATAAGCAAAGTCTT---CCT GTAAGTAACTGTCAACTTCCTGAAATAAAAAGGCAAGGAGAAAATGAAGGCACACTTCAGGCTGTTAATGCAGATTTCTC CCCATGTCTAGTTTCAGATAACCTAGAACAA---CCTATGGGAAGAAGCCATGCTTCTCAGGTTTGCTCTGAGACATCTG ATGAGTTGTTAAATGATGACAAAATAAAGGAAAATAGCAACTTTGCTGAAAGTGACATTAAGGAAAGATCT---GTTTTT AGCAAAAGTGTCCAAAAAGGAGAATTCAGAAAGAGCACTGGCCCTTTAGCCCATCATACATGTTTGGCTCAGGGTCACGA AAGAGGGGCT---------GAGTCCTCAGAAGAGAAAGTGTCTAGTGAG >HumpbackW TGTGGCACAGATACTCATGCCAGCTCATTACAACATGAAAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGTCTCAGCAAAGAGCCAACAGAGCAGATGGGCTGAAAGTAAGGACA CATGTAATGAT---AGGCAGACTCCCAGTACAGAGAAAAAGGTAGTTCTGAATGCTGATCCCCTGTATGGGAGAAAAGAA CTGAATAAGCAGAAACCTGCATGCTCTGACAGTCCTAGAGAT---TCCCAAGAG---TTTCCTTGGATAACAGTGAATAG TCGCATACAGAAAGTTAATGAATGGTTTTCCAGAAGTGATGAAATGTTAACTTCTAACGACTCACGTGATGGGGGATTTG AATCAAACACTGAAGTAGCTTGTGCAGTGGAAGTTCCAAAG------GAAGTTGATGGATATTTGGGTTCTTCAGAGAAA ATAGACTTAATGGCCAGTGATCCTCATGGTGCTTTAATACGTGAAAGTGAAAGAGTCCACTCCAAACCAGTAGAGAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCTAACTTGAGCCACATAGCTGAACATC TAATTATAGGAGCATCTACTGTAGAACCTCAGATAACACAA--------------------------------------- ---------------------GAGCGCCCCCTCACAAATAAACTAAAGCGTAAAAGGAGAAGTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGTCGATTTGGCAGTTATTGCAAAGACTCCTGAAAAAATAACTGAGGGAACTGACCAAACAG AGCAGAAT---------GGTCATGGGATGCATGTTACTAGTAATGGTCCTGAGACTGAAATGAAAGATGATTAT---GTT CAGAAAGAGAAAAATGCTAACCTAACAGAG------TCATTGGAAAAACAATCTGCTTTCAGAACTAAGCCTGAACCTAT AAGCAGCAGTATAGGCAATATGGAACTAGAATTGAATATCCATAGTTCAAAAGCACCTAAA---AATAGGCTGAGGAGGA AGTCCTCTACCAGGAAGATTCATGCACTTGAACTAGTAGTCAGTAGAAACCCAAGCCCACCTAATCATACTGAACTACAA ATTGATAGTTGTTCTAGCAGTGAAGAG---ATGAAGAAAAAA---CATTCCAGCCAAATGCCAGTCAGGCACGGCAAAAA GCTTCAATTCATGGGAGATAAAGCACCTACAACTGGAGCCAAGAAGAGTAACAAGCCACACGAACAAATAAATAAAAGAC TTACCAGTGACGCTTATCCAGAACTAAATTTAACAAACATACCTGGTTTTTTTACTCACTGTTCTAGTTCTAATAAACTT CAAGAGTTTGTTAATCCTAGCCTTCAAAGAGAG---------GAGAAC---CTAGGAAAAATTCAAGTGTCGAATAGTAC CAAAGACCCCAAAGATCTGACATTAAGTGGAGGAAAA---GGTTTGCAA---ATTGAAAGATCTGTAGAGAGTACCGGTA TTTCCTTGGTACCTGATACTGATTATGGCACTCAGGATAGTATCTCATTACTGGAAGCTGACACCCTAGGG---AAGGCA AAG---ACAGCACCAAATCAACATGTGAGTCTGTGTGCAGCAATTGAAAGCCCCAAGGAACTTATCCATGGTTGT---TC TAAAGATATTAGAAACGACACAGAGGACTTTCAGGATCCACTGGGACATCACGTTAAC---CACATTCAGGAGGCGAGCG CAGAAATGGAAGAGAATGAACTTGATACACAGTATTTGCAGAATATGTTCAGGGTTTCAAAGCGTCAGACGTTTGTTCTG TTTTCAAATCCA---------GAAAAGGAATGTGCAACAGTCTGTGCCCGCTCTGGGTCCTTAAGAGAACAAAGTCCAAG AGTCCCTCTTGAATGCAGACAAAAAGAAGAAAATCAGGGAAAGAGTGAGTCTAAAATCAAGCATGTGCGGGCAATTAATA CAACTGTGGACTTCCCTGTTGCTGGTCAAAAAGATAAGAAGCCGAGCGATCATGCCAAACGTAGCCCAAAAAGAGTAACT AGGCTTTGTCAGTCATCACAGTTCAGA---AGCAACAAAACTGAGCTCATTATTGCAAATAAACATGGGATTTCACAAAA CCCATATCTTATACCATCACTTTCTCCCATCAGGTCATCTGTTAAAACTATATGTAAGAAAAAC---CTGTCAGAGGAAA AGTTTGAGGAACCTGTAAGGTCACCTGAAAGAGCAATGGAAAACGAGAGCATCATTCAAAGTACAGTGAGCACAATTAGC CAAAATAACATTCGAGAAAGCACTTTTAAAGAAGTCAGCTCAAGCAGTATTAATGAAGTAGGTTCCAGTACTAATGAAGT AGGCTCTAGTATTAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTCAAGCAAAACTAGRTA GAAACAGAGGACCTAAATTAAGTGCTTTGCTCAGATTAGGTCTTATGCAACCCGAAGTCTATAAGCAAAGTCTT---CCT ATAAGTAACTGTCAACTTCCTGAAATAAAAAGGCAAGGAGAAAGTGAAGGCACACTTCAGGCTGTTAATGCAGATTTCTC CCCAAGTCTAATTTCAGATAACCTAGAACAA---CCTATGGGAAGAAGCCATGCTTCTCAGGTTTGTTCTGAGACATCTG ACGAGTTTTTAAATGATGACAAAATAAGGGAAAATAGCAACTTTGCTGAAAGTGACATTAAGGAAAGATCT---GTTTTT AGCAAAAGTGTCCAAAAAGGAGAATTCAGAAGGAGCCCTGGCCCTTTAGCCCATCATACATGTTTGGCTCAGGGTCACGA AAGAGGGGCT---------GAGTCCTCAGAAGAGAATGTGTCTAGTGAG >Mole TGTGGCATAAATACTCATGCCAGCTTATTACAGCATGAAAACAGCAGTTTATTACTCACTGAAAACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGACTTAGCAAAGAGCCAGCAGAACAGATGGGCTGAAAGTAAAGAAA CATGTAATGAT---AGGCAGACTTCCAGCCCAGAGAAAAGGGTAGACCCGAATGCTGATCCCATGTATGGGAGAAAAGAA CTGAATAAGCAGAAACCTCCATGCTCTGACAGCCCCAGAAAT---TCCCAAGGT---GTTGCCTGGATAACACTGAACAG TAGCATTCGAAAAGTTAATGAGTGGTTTTCCAGAAGTGATGAAATATTAACTTCTGATGAATCTCGTGATGGGGAGTCCC CATCAAATATTGAAATGACTGGTGAAGTAGAAGTTCCAAAC------ACAGTAGATGGATTTTCTGGTTCTTCAGAGAAA ATAGACTTAATGGCCAGCGATCCTCCC---GCTTTAATGTGTAAAAGTGAAAGAGTCCGCACCAAACCAGTAGAAAGTAA T---ATTGAAGATAAGATATTTGGGAAAACCTATCGGAGGAAGACAAGCCTCCCAAACTTGAGCCACGTGGCTGAATATT TAATTACAGGGACATCTGTCACAGAACCTCAGATAGTTCAA--------------------------------------- ---------------------GAGCGTCCCTTCACAAATAGATTAAAACGTAAAAGGAGAACTCTACCAGGCCTTTGTCC TGAGGATTTTATCAAGAAAGTAGATTTGGAAGTTGTTCAGAACACCCCTGAAAAGATAAGTGCGGGAACTGATCAAATGG ATCAGAGT---------GGTCAAGTGATGGATGTTGCTTATAATGGTCATGGGAATGAAACAAAACGTGATTAT---GTT CAGAAAGAGAAAAGTGCTAACCCAGCCGAA------TCTTTAGAAAAAGAATCTACCTTCAGAATTAAAGCTAAGCCCAT AAGTAGCAGTATAAGCAATATGGAACTAGAATTAAATATCCACTCTTCAAAAGCACCTAAGAAGAACAGGCTGAGGAGGA AGTCTTCTACCAAGCATATTCATGCACTTGAACTGGTGGTCAAAAGAAATCCAAGCCCACCTAATCATACAGAACTACAA ATTGATAGCTGTTCTAGCAGTGAAGAG---ATGAAGGAAAGA---AATTCCAACCAAATGCCAGTAAGACACAGCAAAAG GCTTCAACTCATGGAAGATAAAGACCCCGCAACTGAAGCCGTCAAGAGTAACAAGCCAAAAGAACAAATT---AAAAGAT TTGCCAGTGATACTTTGCCAGAACTAAATTCAACACATGTACCTGGCTTTCTTAGCAACTATTCAAGTTCTAATAACCTT GAAGAGTTTTCCAATCCTAGCCTTCAAAGAGAAGAACTAGAAGAGAAC---CTAGGAACAAATCAAGTGTCAAATAATAC CAAAGACCCCAAAGATCCGATACTTAGTGGACAAAGA---GATTTGCAA---GCTGAAAGATCTGGCGAGAGTACCAATA TTTCATTGGTACCTGAGACTGATTTTGGCAGTCAGGATAGTGTCTCATTACTGGAAATTGACATCCTAGGC---AAGGCA AAA---AAAGTGCCGAATCAGTGTGCAAGTCTGTGTACAAAAATTGAAAACTCTAAGGAACTTATTCATAGTTGT---TC TAAAGATACTAGAAATGACACACAGGGCTGTAAGGATCCACTGAAATACGAAGTTAAC---CACACTCAGGAGATAAGGA TAGAGATGGAAGAGAATGAACTTGATACACAGTATTTACAGTCTACGTTCAAAGCTTCAAAGCGTCAATCATTTGCTCTG TCTTCACATCCGGGAAATTCAGAAAAGAAATATCCCCCAGTCTCTGCCCCTTCCAGGTCCTTGAAGAGACAAACTCCAAA AATCACTCTGGAATGTGAACTGAAAGAAGAAAATCAAGGGAAGAAAGAGTCTAAAACCGAGCATGTACAGGCAGTACATA GAATTGCAGACTTAACTCTGGCTTGTCAGAACGATAAG---CCACATGATTCTGCCAAATGTAGCATAAAAGGAGTCTCT AGGCTTTGTCAGTCATCTCAGTTCAGA---GGCAACGAAACAGAAGTCATTGTTGCAAATAAACGTTTAATCTTACAAAA CCCATATCTTATTCCACCACTTTCTTCAATTCAGTCATCTGTTAAAAGTGCTTGTAAGAAAAAC---CTGGCGGAGGAAA AGCTTGAGGAACACTCATGGTCACCCGAAAGAGAAACAGGAAACGGGAGCATCATTGAAAGTACAGTGAGCAGGGTTAGC CAAAATAACAATAGAGAAAATGCTTTTAAGGAAGTCAGCTCAAGTAGTATTAACGAAGTAGGTTCCAGTACTAACGAAGC TGACTCTAGTATTAATGAAGTAGGTTCCAGT---------------------GGTGAAAATATTCAAGCTGAACTAGATG GAAGCAGAGGACCTAAATTAAATGCTATGCTCAGATTGGGTCTTATGCAACCTGAAGTCTATAAGCAAAGTCTT---CCT AAAAGTACTTGTAAACATCCTGAAGTTAAAAGGCAAGGAGAAAATGAAGGCATAGTTCAGGCTGTTCATACAGATTTCTT TCCATGTCTGATTTCAGATAACCAAGAACAA---CCTATGGGAAGTAGTCATGCTTCTCAGGTTTGTTCTGAGACGCCTG AGGACCTGTTAAATGACGAAATAAAGGATAATAACATCAGCTTTGCTGACAGTGGCATTAAGGAAAGATCTGCTGTTTTT AGCAAAAGTTTCCAGAAAGGAGAATTC---AGGAGCCCTAGCCTTTTAGACCAT---ACATGTTTGGCTCAGGACCACGA AAGTGGG------AAATTGGAGTCCCCAGAAGAGACTATGTCTAGTGAG >Hedgehog ---------------------------------CGTGAGAACAGCAGTTTATTACTCACTAAAGGCAAAATGAATGTAGA AAAGGCTGAATTCTGTAGTAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAACAGAGCAGATGGGCTGAAAATATGGAAA CATGTAATGAT---AGGCAGACTCCTAGCCCAGACAAAGAAGTAGATCTGAATGCTGATTCCTTATATGAGAGAAAAGAA CTAAACGAGCAGATCTCTTCATACTCCAGCAGTCCTAAAGAT---TCCAAAGAC---ATTTCTTGGGTAGCACTGAAT-- -AGCATACAGAAAGTGAATGAATGGCTTTCCAGAAGTGATGAACTGTTAACTTCTGATGACTCATATGATAAGGGATCTA AATCAAAAACTGAAGTAACTGTAACAACAGAAGTTCCAAAT------GCAATAGATAGRTTTTTTGGTTCTTCAGAGAAA ATAAACTTAACAGCCAGTGATCCTCATGTTGCTTTAATACGTGAAGGTGAAGGAGTCCACTTCAAACCAGTAAAGAATAA T---ATTGAAGATAAAATATTTGGGAAAACCTATGGGAGGAAGGCAAGCCTTCTTAATTTGAGCCACGTAACTGAAGATG TAATTATAAGG------------GAACCTCAGGTAGCCAAA--------------------------------------- ---------------------GAGCCTCTCCTTGCAACTAAATTAAAACGTAAAAGGAGAACTGATGTAGGTCTTTGTCC TGAGGATTTTATCAAGAAAGTAGATGTGGCAATTGTTCAGAAGACTCCTGAAAAGATAATCAAGAGACCTGGCCAACTGG ATCAAAGT---------GACCAAGTAATGAATATTGCTACTAATGGTCATGAAACTGAAACAAAGAGTGATTAT---GTT CAGAAGGAGAAAAATGCTAACCCAGCAGAA------TCACCAGACAAAGAATCTGCTTTTAGAAATAAACCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTAGAATTAAATGTCCACAGTTCAAAAGCACCTAAGAAGAATAAACTCAGGAGAA AGTCATCTGCCAGGCATATTCATGCACTTGAAGTAGTAGTCAATAAAAACTCAAGCCCACCTAGCCATACAGAACTACAA ATTGATAGCTGTTCTAGCAATGAAGAG---ATGAGGGGGGTG---AAAGCTGATCAAATGCCAGTCAGGCACAGCAAACA ACTTCCACTCATTGAAGACAAAGAACCTGCAACTAGAGCCTTTAGTAGTAGCAAGTCAAATGAACAAATAAGTAAACAGT TTGTTGGTGAGACTTTTTCAGACCTAAATTTAACAAACATCCCTGGTTTTCTTACCAGCTGTTCAAGTTCCAATAAACAT CAGGAATGTATTAATCCTAACCTACAAAGAGAGGTATTAGGAGAAAGC---CGTGGGACTATTCAAGTGTGTAATAATAC CAAAAACCCTAAAGATCTGATAGTAAGTGGAAAGAGA---GGTTTACAA---ATTGAAAGATCTGTAGAGAGTCCT---- --------GTAGAGAACACTGACTATGGCAGTCAGGATAGTATCTCATTACTGGAAACTGATACTCTAGGG---AAGGCA AAA---AAGACACCAAATCAATGTGTAAGTCTGTGTGTAGCAACTGAAACCCCCAAAGAACTTAGCCATAGTTGT---TC TAAAGATACTAGAAATGACACTGAAGGCTTTAGGGATTCACTCAGATGTGAAGTTGAT---CACACGCAGGAGACAAGCA CAGAACTGGAGGAGAGTGAACTTGATACACAGTATTTACAGAATACCTTCAAGGTTTCAAAACGTCGGTCATTTGCTCTG TTTTCAAGTCCAGAGAATTCAGAAAAGGCATGTACAAGAGGCTCTGTCCATTCTAAGTCTTTAAGGAAACAAAGTCCAAA AGTTATTCTGGACTGTGAACAAAAAGAAGAAAATCAAGGAGAGAAAGCATCTGAAATCAAGTATTTGCCATCAGAACATA CAACTACAGGCTTTCCTGTGGTGTGTTATAAAGATACA---TCAGGTGATTATGCCAAATGTAGCGTAAAAGGAGTCTCC AGGCATTGTCAGCCATCTCGGTTCAGA---GGCAGTGAACCTGAACTCATTGTTGCAAATAAAAATTTAATTTTACAAAA CCTATATCATATACCAACACTTCCTACCATCATGTCATCTACTAAGAGTATATGCAAGAAAAAC---CTGTCTGAGGAAA AT------------TCACTGTCGCCTGAAAGAGCAGTGACAAACAAAAGCATCATCCAAAGTACAGTGAACACCATTAGC CAGACTAATGCCAGTGAAAATGCTCTTAAAGATGTCAGTTCAAGCAGTGTTAATGATATGGGTTCCAGTACTAATGAAGT AGGTTCCAGT------------------------------------------AGTGAAAACATTCAAGCTAAACTATGTA GAAACAGAGGACCCAGATTAAATGCTACTCTTAGAGCAAGTCTTATGCAACCTGAAGTCTTTGAGCAGTGTCTT---CTG ATGAGTAACTGTAAACATTCTGAAATGAAAAGACAAGGAGAAAATGAAGGTGTTATTCAGACTGTTAATATAGAATCCGA TTCATGCCCAAGACCAGATAACTTAGAACAA---CCGGTGGAAACTAGTCAT---------GTTTGTTCTGAAACACCTG ACGATCTGTTAAATGACGATGAAATGAAGGAAAATACAAGCTTTACTGAAAGTGGCATTAAGGAACAATCTGCTGTTTTT GGCAAAAGTACCCAGAAAGGT---TTCAGAAGGAGCCCTAGCCCTTTAGGCCAC---ACATGTTTGAGACAGGATCAGCA AAGAGGGGCACAAAAATCAGAGCCCTCTGAAGATTTCATGTCTAGTGAG >TreeShrew TGTGGCATAAATACTTATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAGGACAGAATGAATGTAGA AAAGGCTGAATTGTGTAATAAAAGCCAACAACCTGACTTAGCAAGGAGCCAGCAGAGCAGATGGACTGAAAATAAGGAAA CATGTAATGAT---AGGCAGATTCCCAGCACAGAAAAAAAGGTAGATCTAAATGCTGATCCCCTGTGTGGGAAGAAAAAA CAAGCTAAGCAGAAACYGCTATGTTCTAACAGTCCTAGAGAT---GACCAAGAT---TCTCCTTGGATAACTCTAAATAG TAGCATTCAGAAAGTTAATGAATGGTTTTCCAGAAGTGATGAAATGTTAACTTCTAACGACTCACATGATGGTGAGTCTG AA------------ATAGCTGGTGCATTYGAAGYTCCAAAT------AAAGTAGATGAATATTCTGGTTCTTCAGAAAAA ATAGACTTAATGGCCAACAATCTTCATGATGCTTTAATAAGTAAAAGTGAAGGAATCTACTCCAAACCAGTAGAGGGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAAGCAAGTCTTCCTAACTTGAGCCGTGTAACTGATGATC TAATTAGAGGGGCATTTGTTACAGAGCCTGAGATAACTCGA--------------------------------------- ---------------------GAGCGTCCCTTCACAAATAAATTAAAGCGGAAAAGGAGAACTATATCAGGCCTTCATCC TGAAGATTTTATCAAGAAAACAGATTTGGCAGTTGTTCAAAAGACTCCTGAAAAGATAAATCAGAGAACTGACCAAATAG AGCATAAT---------GGTCAGGTGATGAGTATTGCTAATAGTGGTCATGAGAATGAAACAAAAGGTGATTAT---ATT TCGAAAGAGAAAAATGCTAACCCAATGGAA------TCATTAGAAAAAGAATCTGCTCTCAGAACTAAAGCTGAGCCCAT AAGCAGCAGTGTAAGCAATATGGAACTAGAAATAAATAACCACAGTTCAGAAGCACCTAAGAAGAATAGGCTGAGGAGAA AGTTTTCTGCTAGGCATATTCGCACACTTGAACTAGTAGACAATAAAAGTCCAAGCCCACCTAATCGTACTGAACTACAA ATTGACAGTTATTCTAGCGGTGAAGAG---AGAAAGAAAAAG---GGT---GAGCAAATGCCAGTTGGACACAGCAGAAA GTTTCAACTTGAGGAAGAGAAAGAACCTACAACTGGAGCCAAGAAAAATAACCAGCCAAATACAGAAATAAGTGAAAGAC ATGCCAGTGGTGTTATCCCAGATCTGAAGTTAACAAACATACCTGGTTTTTTCACAAACTCTTCGAGTTCTAATAAACTT CCAGAATTTGTCCATCGTAGCCTTCAAAGAGAAAAA---GAAGAGAAC---CGAGAAACAATTCAAATATCCAGTAGTAC C---------AAAGATCTGGTATTAAGGGGAGAAAGG---GGTTTGCAA---GATGTAAGGTCTGCAGAGAGTACCAGTA TTTCTTTGGTACCTGATACTGATGATAACACCCAGGATAGCATCTCATTACTAGATGCTAACCCCCTAGCTAGGAAGGCA AAA---ACAGCACCAAATCAATGTGTAAATCAGAGTGCAACAACTGAAAACCCCAAGGAACTTATACACAGTTGT---TC TAAAACTACTAGGAAT------GAAGGCTTCAAGGATCCATTGAAAAGTGAAGTTAAT---CATATTCAGGAGATGAGTG TAGAAATGGAGGAGAGTGAACTTGATACTCAGTATTTACAGAATACATTCAGGAGTTCAAAGCGTCAGTCATTTGCTCTG TCTTCAAATCCAGGAAATCCAGAAAAGGAACATGTCTGTGTT-------------------------------------- -------------------------------AAAGAAAGTCTGAAAGAGTCTAACATCCAACATATACAGGCAGTTAGTA CC---------------ATGGTTTTTCAGAAAGATAAG---CTAGGTGATTTTGCTACATCTGGCATTAAAGAAGTCCCT AGACTTTGTCCATCATCTCAGTTCAGA---GGCAATGAAACTGATCTCATTACTGCAAATAAACCTGAAGTTTCACAAAA CCCGTATCATATGCCATTACTTTATCCTGTCAAGTCACCTATTATAACTAAAAGTAAGAAAAGC---CTGTCAGAGGAAG GGTTTGAGGAACAGGCAATGTCACTTGAAAGAGCAATGGAAAATGAGAACATCATTCAAAGTACAGTGAGCACAATTAGC CAAGATAACATTAGAGAAGGTGCTTTTAAAGAAGCCAGCTCAAGCAGTATTAATGAAATAGGTCCTAGTACTAATGAAGG AAGCTCTAGTATTAATGAGGTAGGTTCCAGT---------------------GGTGAAAACATTCAAGCAGAACTAGGTA AAAAGAGAGGATCCAAATTAAATGCTGTGCTTAGATTAGGTCTTATGCAACCCGAAGTCTATAAGCAAAGTCTT---CCT TTAAGTAATCATAATGATCCTGAAATGAAAAGACAAGAAAAAAATGAAGGAGGAGTTCAGGCTATTAAA---GATTTACC TCCATGTCTAATTTCAGATAATCAAGAGCAT------ATGGGAAGTAGCCATGCTTCTCAGATTTGTTCTGAGACACCTG ATGATCTGTTAGATGATGATGAAGGAAAAGAAAAT---AGCTTTGCTGAGGTTGATGTTAAGGAAAGATCTGCTGTTTTT GGCAAAACTGTCCAGAGAAGAGAGTTAAGAAGGAGCTCTAGCCCTTTAACTCGT---GCATGTTTGACTGAGGGTCAGCA AACAGGAGCCCAGAAATTAGATTCATCAGAAGAGAACCTATCTAGTGAG >FlyingLem TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACGCACTAAAGACAGAATAAATGTTGA AAAGACTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAGGAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACGCCCAGCACAGAGAAAAAGATAGATCTAAATGCTGATTCCCAGCATGGGAGAAAAGAA CGGAATATGCAGAAACCTCCATACCCTGAGAGTCCTAGAGAT---ACCCAAGAT---GTTCCTTGGATAACACTAAACAG CAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGAAATTTTAGCTTCTGATGACTCACGTGACAGGGTGTCTG AATCAAATGCCAAAGTAGCTGGTGCATTAGAAGTTCCAAAT------GATGTAGATGGATATTCTGATTCTTCAGAGAAA GTTGATTTAATGGCCAGTGATCCTCATGATGCTTTAATATGTAAAAGTGAAAGAATCCACTCCAGACCAGTAGAGAGTAA T---ATCAAAGATAAAATATTTGGGAAAACCTATCAGAGGAAGACAAGCCTCCCTAACTTGAGCCACGTAAATGAAGATC TAATTATAGGAGCATTTGTTACAGAACCACAGATAACACAA--------------------------------------- ---------------------GAGCGTCCCCTCACAAATAAGGTAAAGCCTAAAAGGAGAACTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGCAGACTTGGCAGTTGTTCAAAAAACTCCTGAAAAGATAAATCAGGGAATTGACCAAATGG AGCAGAAT---------GATCGAGTGATGAATATTATTAATAGTGGTCATGAGAATGAAACAAAGGATGATTAT---GTT CAGAAAGAGAAAAATGCTAACCCAACAGAA------TCATTGGAAAAAGAATCTGCTTTCAGAACTAAAGCAGAACCTAT AAGCAGCAGTATAAGCAATATGGAAATAGAATTAAATATCCACAATTCAAAACCATCTAAGAAGAATAGGCTGAGGAAGA TGTCCTCTACTAGGCATATTCATGCACTTGAACTAGTAGTCAATAGAAATCCAAGCCCACCTAATTATACTGAACTACAA ATTGATAGTTGTTCTAGCAGTGAAGAA---ATAGAGAAAAAA---AATTCCAGCCAAATGCCAGTCAGGCACAGCAGAAA GCTTCAACTCATGGAAAATAAAGAACCTGCAACTGGAGCCAAGAAGAGTAACAAGCCAAATGAACAAATAAGTAGAAGAC ATTCCAGTAATGCTTTCCCAGAACTGCGGTTAACAAATGTACCTGTTTTTTTTGCTAACTGTTCAAGTTCTAATAAACTT CAAGAATTTATCGATCCTAGCCTTCAAAGAGAAGAAATAGAAGAGAAC---CTAGAAACAATTCATGTGTCTAATAGTGC CAAAGACCCCAAAGATTTGGTGTTAAGTGGGGAGAAG---GGTTTGCAA---ACTGAAAGATCTGTAGAGAGTACCAGTA TTTCATTAGTACCTGATACTGATTATGGCACTCAAGACAGTATCTCAATATTAGAAGCTAACATCCTAGGG---AAGGCA AAA---ACAGCACCAAGTCAACATGCAAATCAGTGTGCAGCAATTGAAAACCCCAAAGAACTTATCCATGGTTGT---CC TAAAGGTACTAGAAATGACACAGAGGATTTTAAGGATCCATTGAGATGTGGAGTTGAC---CACATTCAGAAGACAAGCA TAGAAATGCAAGAGAGTGAACTTGATACTCAGTATTTACAAAATATATTCAAGGTTTCAAAACGTCAGTCATTTGCTCTC TTTTCAAATCCAGGAAATCCAGAAAAGGAGTGTGCAACAGTCTATGCCCACTCCAGGTTGTTAAGGAAACAAAGTCCAAA AGTCACTCCTGAATGTGAACAAAAAGAAGAAAATGAGGGAAATAAAGAGTCTAAAATCAAGCACATACAGGCAGTTAATA CCACTGTGGGCTTTTCTGTCCTTTGTCAGAATGTTAAGAAGCCAGGTGATTATGCCAAATTTAGCATTAAAGGAGTCTCT AGGCATTGTTCATCATCTCAGTTCAGA---GGCAATGAAACTGAACTCATTACTGCAAATAAACATGGAATTTTACAAAA CTCATGTCATATGTCATCACTTTCCCCCATCAGGTCATCTGTTAAAATTAAATGTAAGAAGAAC---CTGTCAGAGGAAA GGTTTGAGGAACATTCAGTGTCACCTGAAAGAGCAATGGCAAACAAGAGAATCATTCAAAGTACAGTGAACACAATTAGC CAAAATAACATTAGAGACAGTGCTTCTAAAGAAGCCAGCTCAAGCAGTATTAATGAAGTAGGTTCCAGTACTAATGAAGT AGGCTCCAGTATTAATGAAGTAGGTCCCAGT---------------------GGTGAAAACATTCAAGCAGAACTAGGTA GAAACAGAGGACCTAAATTAAGTGCTATGCTTAGATTAGGCCTCATGCAACCTGAAGTTTACAAGCAAAATCTT---CCT TTAGGTAATTGTAAACATCCTGAAATA---AGGCAAGAAGAAAATGAAGGAATAGTTCAGGCTGTTAATACAAATCTGTC TCTGTGCCTAATTTCACATAACCTCGAACAA---CCTATGGAAAGTAGTCATGCTTCCCAGGTTTGTTCTGAGACACCTG ATGACCTGTTAGATGGTGATGAGATAAAGGAAAACACCAGCTTTGCTGAAAGTGACAGTAAGGAAAGATCTGCTGTTTTT AGCAAAAGTGTCCAGAGAGGAGAGTTAAGCAGGAGCCCTAGCCCTTTTGCCCAA---ACATGTTTGGCTCAGGGTCACCA AAGAGGAGCCAGGAAATTAGAGTCTTCTGAAGAGAACGTATCTAGTGAG >Galago TGTGGCAAAAATACTCATGCCAGCTCATTACAGCATGAGAGCAGCAGTTTATTACTCACTAAAGACAAAATGAATGTAGA AAAGGCTGAATTTTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAACAGAGCAGATCGGCTCAAAGTAAGGAAA CATGCAATGAT---AGGCACACTTGCAGCCCTGAGCAAAAGGTAGATCTGAATACTGCTCCCCCATATGGGAGAAAAGAA CAGAATAAGGAGAAACTTCTATGCTCCAAGAATCCTAGAGAT---AGCCAAGAT---GTTCCTTGGATAACACTAAATAG CAGCATTCAGAAAGTTAATGAATGGTTTTCTAGAAGTGATGAAATGTTAACTTCTGATGACTCACATGATGAGGGTTCTG AATCACATGCTGAAGTAGCTGGAGCCTTAGAAGTTCCAAGT------GAAGTAGATGGATATTCCAGTTCCTCAGAGAAA ATAGACTTACTGGCCAGTGATCCTCATTATCCTATAATATGTAAAAGTGAAAGAGTTCACTCCAAACCAATAAAGAGTAA A---GTTGAAGATAAAATATTTGGGAAAACTTATCGGAGGAAGGCAAGCCTCCCTAACTTAAGCCATGTAACTGAAAATC TAATTATAAGAGCAGCTGCTACTGAGCCACAGATAACACAA--------------------------------------- ---------------------GAGTGTTCCCTCACAAATAAATTAAAACGTAAAAGGAGAACTACATCAGGTCTTTGTCC TGAGGATTTTATCAAGAAGGCAGATTTGGCAGTTGTTCAAAAGACACCTGAAAAGAGAATTCAGGGAACTAACCAAGTGG ATCAGAAT---------AGTCACGTGGTAAATATTACTAATAGTGGTTATGAGAATGAAACAAAAGGTGATTAT---GTT CAGAATGAAAAAAATGCTAACTCAACAGAA------TCATTGGAAAAAGAATCTTCTCTCGGAACTAAAGCTGAACCTAT AAGCAGCAGTATAAGTAATATGAAATTAGAATTAAATATTCACAATTCAAAAGCAAGTAAAAAGAAAAGGCTGAGGAAGA AGTCTTCTAGCAGGCATATTCGTGCACTTGAACTAGTAGTCAATAAAAATCCAAGCCCTCCTAATCATACCAACCTACAA ATTGACAGTTGTTCTAGCAGTGAAGAA---ATAAAGGATAAA---AGTTCTGACCAAATACCAGTCAGGCATAGCAGAAA GCCTGGACTCATGGAAGATAGAGAACCTGCAACTGGAGCCAAGAAAAGTAACAAGCCAAATGAGCAAATAAGTAAAAGAC ATGTCAGTGATACTTTCCCAGAAGTGGCATTAACAAATATATCTAGTTTTTTTACTAACTGTTCAGGTTCTAATAGACTT AAAGAATTTGTCAATCCTAGCCTTCAAAGAAAAAAAACAGAAGAGAACTTAGAAGAAACAATTCAAGTGTCTAATAGTAC CAAAGGTCCGGTGTTAAGTGGAGAAAGGGTTTTGCAA---ATTGAAAGT---GAAGAAAGATCTATAAAAAGCACCAGTA TTTCATTGGTACCTGATACTGATTATGGTACTCAGGACAGTAACTCGTTACTGAAAGTTAAAGTCTTACGG---AAGGTG AAA---ACAGCACCAAATAAACATGCAAGTCAGGGTACAGCCACTGAAAACCCCAAGGAACTAATCCATGGTTGC---TC TAAAGATACTGGAAATGACACAGAGGGCTATAAGGATCCATTGAGACATGAAATTAAC---CACATTCAGAAGATAAGCA TGGAAATGGAAGACAGTGAACTTGATACTCAGTATTTACAGAATACATTCAAGTTTTCAAAGCGTCAGTCGTTTGCTCTG TTTTCAAACCTAGGA---------AAGGAATGTGCAACAGTCTGTGCCCAGTCTCTCTCTGCGTCCTTAAGAAAAGGTTC AAAAGTCATTCTTGAATGTGAACAAATAGAAAATCCAGGAATGAAAGAGCCTAAAATCAAGCATATACAGGGAAATAATA TCAATACAGGCTTCTCTGTAGTTTGTCAGAAAGATAAGAAAACAGATGATTATGCCAAATACAGCATCAAAGAAGCATCT AGGTTTTGTTTGTCAAATCAGTTTCGA---GACAATGAAACTGAATCCATTACTGTAAATAAACTTGGAATTTTACAAAA CCTCTATCATATACCACCACTTTCTCCTATCAGGCTATTTGATAAAACTAAATGTAATACAAAC---CTGTTAGAGGAAA GGTTTGAAGAACATTCAGTGTTACCTGAAAAAGCAGTAGGAAACGAGAACACCGTTCCAAGTACAATGAATACAATTAAC CAAAATAAC---AGAGAAAGTGCTTATAAAGAAGCCAGTTCAAGCAGTATCAATGAAGTAAGCTCGAGTACTAATGAAGT GGGCTCCAGTGTTAACGAAGTAGGCCCCAGT---------------------AGTGAAAACATTCAAGCAGAACTAGATA AAAACAGAGGACCTAAGTTGAATGCTGTGCTTAGATTAGGTCTTATGCAACCTGAAGTCTATAAACAAAATCTT---CCT ATAAGTAATTGTGAACATCCTAAAATAAAAGGGCAAGAAGAAAATGGA---GTAGTTCAACCTGTTAATCCAGATTTTTC TTCATGTCTAATTTCAGATAACCTAGAACAA---CCTACGAGAAGTAGTCATGCTTCTCAGCTTTGTTCTGAGACACCTG ATGACTTATTAGTTGATGATGAACTAAAGGAAAATACCAGTTTTGCTGAAAATAACATTAAGGAAAGATCTGCTGTTTTT AGCAAAAATGTCATGAGAAGAGAGATTAGCAGGAGCCCTAGCCCTTTAGCCCAT---ATACATTTGACTCAGGCTCACCA AAGAGAGGTTAGGAAATTAGAGTCCTCAGAAGAGAACATGTCTAGTGAA >HowlerMon TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTGTTACTCACTAAAGACACACTGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAACATAACAGATGGGCTGAAAGTGAGGAAA CATGTAATGAT---AGGCAGACTCCCAGCACAGAGAAAAAGGTAGATGTGGATGCTGATCCCCTGCATGGGAGAAAAGAA TGGAATAAGCAGAAACCTCCGTGCTCTGAGAATCCTAGAGATGATACTGAAGAT---GTTGCTTGGATAATGCTAAATAG CAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGAACTGTTAACTTCTGATGACTCACATGATGGGGGGTCTG AATCAAATGCCAAAGTAGCTGAAGCATTGGAAGTTCTAAAT------GAGGTAGATGGATATTCTAGTTCTTCAGAGAAA ATAGACTTACTGGCCAGTGATCCTCATGATCATTTGATATGTAAAAGTGAAAGAGTTCACTGCAAATCAGTAGAGAGTAG T---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCTAACTTGAGCCACGTAACTGAAAATC TAATTATAGGAGCATTTGTTACTGAGCCACAGATAATACAA--------------------------------------- ---------------------GAGCATCCTCTCACAAATAAATTAAAGCGTAAAAGGAGAGTTACATCAGGACTTCATCC TGAGGATTTTATCAAGAAAGCAGATTTGGCAGTT---CAAAAGACTCCTGAAAAGATAAATCAGGGAACTAACCAAACAG AGCGGAAT---------GATCAAGTGATGAATATTACTAACAGTGGTCATGAGAATAAAACAAAAGGTGATTCT---ATT CAGAATGAGAACAATCCTAACCCAGTAGAA------TCACTGGAAAAAGAATCA---TTCAAAAGTAAAGCTGAACCTAT AAGCAGTAGTATAAGCAATATGGAATTAGAATTGAATGTCCACAATTCCAAAGCATCTAAAAAGAATAGGCTGAGAAGGA AGTCTTCTACCAGGCATATTCATGAGCTTGAACTAGTAGTCAGTAGAAATCTAAGCCCACCTAATTATACTGAAGTACAA ATTGATAGTTGTTCTAGCAGTGAAGAG---ATAAAGAAAAAA---AATTACAACCAAATGCCAGTCAGGCACAGCAGAAA GCTACAACTCATGGAAGATAAAGAACGTGCAGCTAGAGCCAAAAAGAGTAGCAAGCCAAATGAACAAACAAGTAAAAGAC ATGCCAGTGATACTTTCCCAGAACTGAGGTTAACAAACATACCTGGTTCTTTTACTAACTGTTCAAATACTAATGAATTT AAAGAATTTGTCAATCCTAGCCTTCCAAGAGAACAAACAGAAGAGAAA---CTAGAAACAGTTAAACTGTCTAATAATGC CAAAGACCCCAAAGATCTCATGTTAAGTGGAGAAAGT---GTTTTGCAA---ATTGAAAGATCTGTAGAGAGTAGCAGTA TTTTGTTGATACCTGGTACTGATTATGGCACTCAGGAAAGTATCTCATTACTGGAAGTTAGCACTCTGGGG---AAGGCA AAA---ACAGAACCAAATAAATGTGTGAGTCAGTGTGCAGCATTTGAAAACCCCAAGGAACTAATTCATGGTTGT---TC TAAAGATACTAGAAATGGCACAGAAGGCTTGAAGTATCCATTGGGACCTGAAGTTAAC---TACAGTCAGGAAACAAGCA TAGATATGAGAGAAAGTGAACTTGATACTCAATATTTGCAGAATACATTCAAGGTTTCAAAGCGCCAGTCATTTGCTCTG TTTTCAAATCCAGGAAATCCAGAAAAGGAATGTGCAACATTCTCTGCCTGCTCTAGGTCCTTAAAGAAACAAAGTCCAAA GGTCACTCCTGAATGTGAACAAAAGGAAGAAAATCAAGGAGAGAAAGAGTCTAATATCGAGCTTGTAGAGACAGTTAATA CCACTGCAGGCTTTCCTATGGTTTGTCAGAAAGATAAG---CCAGTTGATTATGCCAGATGT---ATCGAAGGAGGCTCT AGGCTTTGTCTATCATCTCAGTTCAGA---GGCAACGAAACTGGACTCATTATTCCAAATAAACATGGACTTTTACAGAA CCCATATCATATGTCACCGCTTATTCCCACCAGGTCATTTGTTAAAACTAAATGTAAGAAAAAC---CTGCTAGAAGAAA ACTCTGAGGAACATTCAATGTCACCTGAAAGAGCAATGGGAAACAAGAACATCATTCCAAGTACAGTGAGCACAATTAGC CATAATAAC---AGAGAAAATGCTTTTAAAGAAACCAGCTCAAGCAGTATTTATGAAGTAGGTTCCAGTACTAATGAAGC AGGTTCTAGTACTAATGAAGTAGGCTCCAGTATTAATGAAGTAGGTTCCAGTGATGAAAACATTCAAGCAGAGCTAGGTA GAAACAGAAGGCCAAAATTGAATGCTATGCTTAGATTAGGGCTTCTGCAACCTGAGATTTGTAAGCAAAGTCTT---CCT ATAAGTGATTGTAAACATCCTGAAATTAAAAAGCAAGAACATGAAGAA---GTAGTTCAGACTGTTAATACAGACGTCTC TCTATGTCTGATTTCATATAACCTAGAACAG---CATATGGGAAGCAGTCATACATCTCAGGTTTGTTCTGAGACACCTG ACAACCTGTTAGATGATGGTGAAATAAAGGAAGATACTAGTTTTGCTGAATATGGCATTAAGGAGACTTCTACTGTTTTT AGCAAAAGTGTCCAGAGAGGAGAGCTCAGCAGGAGCCCTAGCCCTTTCACCCAT---ACACATTTGGCTCAGGTTTACCA AAGAGGGGCCAAGAAATTAGAGTCCTCGGAAGAGAATTTATCTAGTGAG >Rhesus TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAAC---AGTTTGTTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTGGCAAGGAGCCAACATAACAGATGGACTGGAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCCAGCACAGAGAAAAAGGTAGATCTGAATGCTAATGCCCTGTATGAGAGAAAAGAA TGGAATAAGCAAAAACTGCCATGCTCTGAGAATCCTAGAGAC---ACTGAAGAT---GTTCCTTGGATAACACTAAATAG CAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGAACTGTTAAGTTCTGATGACTCACATGATGGGGGGTCTG AATCAAATGCCAAAGTAGCTGATGTATTGGACGTTCTAAAT------GAGGTAGATGAATATTCTGGTTCTTCAGAGAAA ATAGACTTACTGGCCAGTGATCCTCATGAGCCTTTAATATGTAAAAGTGAAAGAGTTCACTCCAGTTCAGTAGAGAGTAA T---ATTAAAGACAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAACCTTCCCAATTTAAGCCATGTAACTGAAAATC TAATTATAGGAGCACTTGTTACTGAGTCACAGATAATGCAA--------------------------------------- ---------------------GAGCGTCCCCTCACAAATAAATTAAAGCGTAAAAGGAGAACTACATCAGGTCTTCATCC TGAGGATTTTATAAAGAAAGCAGATTTGGCAGTT---CAAAAGACTCCTGAAATAATAAATCAGGGAACTAACCAAATGG AGCAGAAT---------GGTCAAGTGATGAATATTACTAATAGTGCTCATGAGAATAAAACAAAAGGTGATTCT---ATT CAGAATGAGAAAAATCCTAACCCAATAGAA------TCACTGGAAGAAGAATCTGCTTTCAAAACTAAAGCTGAACCTAT AAGCAGCAGTATAAACAATATGGAACTAGAATTAAATATCCACAATTCAAAAGCACCTAAAAAAAATAGGCTGAGGAGGA AGTCTTCTACCAGGCATATTCATGCGCTTGAACTAGTAGTCAGTAGAAATCTAAGCCCACCTAACTGTACTGAACTACAA ATTGATAGTTGTTCTAGCAGTGAAGAG---ATAAAGAAAAAA---AATTACAACCAAATGCCAGTCAGGCACAGCAGAAA CCTACAACTCATGGAAGATAAAGAATCTGCAACTGGAGCCAAGAAGAGTAACAAGCCAAATGAACAGACAAGTAAAAGAC ATGCCAGTGATACTTTCCCAGAACTGAAGTTAACAAAGGTACCTGGTTCTTTTACTAACTGTTCAAATACTAGTGAA--- AAAGAATTTGTCAATCCTAGCCTTTCAAGAGAAGAAAAAGAAGAGAAA---CTAGAAACAGTTAAAGTGTCTAATAATGC CAAAGACCCCAAAGATCTCATCTTAAGTGGAGAAAGG---GTTTTACAA---ACTGAAAGATCTGTAGAGAGTAGCAGTA TTTCATTGGTACCTGGTACCGATTATGGCACTCAGGAAAGTATCTCATTACTGGAAGTTAGCACTCTAGGG---AAGGCA AAA---ACAGAACGAAATAAATGTATGAGTCAGTGTGCAGCATTTGAAAACCCCAAGGAACTAATTCATGGTTGT---TC TGAAGATACTAGAAATGACACAGAAGGCTTTAAGTATCCATTGGGAAGTGAAGTTAAC---CACAGTCAGGAAACAAGCA TAGAAATAGAAGAAAGTGAACTTGATACTCAGTATTTGCAGAATACATTCAAGGTTTCAAAGCGCCAGTCCTTTGCTCTG TTTTCAAATCCAGGAAATCCAGAAGAGGAATGTGCAACATTCTCTGCCCACTCTAGGTCCTTAAAGAAACAAAGTCCAAA AGTTACTTCTGAATGTGAACAAAAGGAAGAAAATCAAGGAAAGAAACAGTCTAATATCAAGCCTGTACAGACAGTTAATA TCACTGCAGGCTTTTCTGTGGTTTGTCAGAAAGATAAG---CCAGTTGATAATGCCAAATGTAGTATCAAAGGAGGCTCT AGGTTTTGTCTATCATCTCAGTTCAGA---GGCAACGAAACTGGACTCATTACTCCAAATAAACATGGACTGTTACAAAA CCCATACCATATACCACCACTTTTTCCTGTCAAGTCATTTGTTAAAACTAAATGTAACAAAAAC---CTGCTAGAGGAAA ACTCTGAGGAACATTCAGTGTCACCTGAAAGAGCAGTGGGAAACAAGAACATCATTCCAAGTACAGTGAGCACAATTAGC CATAATAACATTAGAGAAAATGCTTTTAAAGAAGCCAGCTCGAGCAATATTAATGAAGTAGGTTCCAGTACTAATGAAGT GGGCTCCAGTATTAATGAAGTAGGTTCCAGT---------------------GATGAAAACATTCAAGCAGAACTAGGTA GAAACAGAGGGCCAAAATTGAATGCTGTGCTTAGATTAGGGCTTTTGCAACCTGAGGTCTGTAAACAAAGTCTT---CCT ATAAGTAATTGTAAGCATCCTGAAATAAAAAAGCAAGAACATGAAGAA---TTAGTTCAGACTGTTAATACAGACTTCTC TCCATGTCTGATTTCAGATAACCTAGAACAG---CCTATGGGAAGTAGTCATGCGTCTGAGGTTTGTTCTGAGACTCCTG ATGATCTGTTAGATGATGGTGAAATAAAGGAAGATACTAGTTTTGCTGAAAATGACATTAAGGAGAGTTCTGCTGTTTTT AGCAAAAGCATCCAGAGAGGAGAGCTCAGCAGGAGCCCTAGCCCTTTCACCCAT---ACACATTTAGCTCAGGGTTACCG AAAAGAGGCCAAGAAATTAGAGTCCTCAGAAGAGAACTTATCTAGTGAG >Orangutan TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAACATAACAGATGGGCTGGAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCCAGCACAGAAAAAAAGGTAGACCTGAATGCTGATCCCCTGTGTGAGAGAAAAGAA TGGAATAAGCAGAAACTGCCATGCTCAGAGAATCCTAGAGAT---ACTGAAGAT---GTTCCTTGGATAACACTAAATAG CAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGACGAACTGTTAGGTTCTGATGACTCACATGATGGGAGGTCTG AATCAAATGCCAAAGTAGCGGATGTATTGGACGTTCTAAAT------GAGGTAGATGAATATTCTGGTTCTTCAGAGAAA ATAGACTTACTGGCCAGTGATCCTCATGAGGCTTTAATTTGTAAAAGTGAAAGAGTTCACTCCAAATCAGTAGAGAGTAA T---ATTGAAGACAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCCAACTTAAGCCATGTAACTGAAAATC TAATTATAGGAGCATTTGTTACTGAGCCACAGATAATACAA--------------------------------------- ---------------------GAGCGTCCCCTCACAAATAAATTAAAGCGTAAAAGGAGAGCTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGCAGATTTGGCAGTT---CAAAAGACTCCTGAAATGATAAATCAGGGAACTAACCAAATGG AGCAGAAT---------GGTCAAGTGATGAATATTACTAATAGTGGTCATGAGAATAAAACAAAAGGTGATTCT---ATT CAGAATGAGAAAAATCCTAACCCAATAGAA------TCACTCGAAAAAGAATCTGCTTTCAAAACAAAAGCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTCGAATTAAATATCCATAATTCAAAAGCACCTAAAAAGAATAGGCTGAGGAGGA AGTCTTCTACCAGGCATATTCATGCGCTTGAACTAGTAGTCAGTAGAAATCTAAGCCCACCTAATTGTACTGAATTGCAA ATTGATAGTTGTTCTAGCAGTGAAGAG---ATAAAGAAAAAA---AAATACAACCAAATGCCAGTCAGGCACAGCAGAAA CCTACAACTCATGGAAGATAAAGAACCTGCAACTGGAGCCAAGAAGAGTAACAAGCCAAATGAACAGACAAGTAAAAGAC ATGACAGCGATACTTTCCCAGAGCTGAAGTTAACAAATGCACCTGGTTCTTTTACTAACTGTTCAAATACCAGTGAGCTT AAAGAATTTGTCAATCCTAGCCTTCCAAGAGAAGAAAAAGAAGAGAAA---CTAGGAACAGTTAAAGTGTCTAATAATGC CAAAGACCCCAAAGATCTCATGTTAAGTGGAGGAAGG---GTTTTGCAA---ACTGAAAGATCTGTAGAGAGTAGCAGTA TTTCATTGGTACCTGGTACTGATTATGGCACTCAGGAAAGTATCTCGTTACTGGAAGTTAGCACTCTAGGG---AAGGCA AAA---ACAGAACCAAATAAATGTGTGAGTCAGTGTGCAGCATTTGAAAACCCCAAGGAACTAATTCATGGTTGT---TT CAAAGATACTAGAAATGACACAGAAGGGTTTAAGTATCCATTGGGACATGAAGTTAAC---CACAGTCAGGAAACAAGCA TAGAAATGGAAGAAAGTGAACTTGATACTCAGTATTTGCAGAATACATTCAAGGTTTCAAAGCGCCAGTCATTTGCTCTG TTTTCAAATCCAGGAAATCCAGAAGAGGAATGTGCAACATTCTCTGCCCACTCTAGGTCCTTAAAGAAACAAAGTCCAAA AGTCACTTTTGAATGTGAACAAAAGGAAGAAAATCAAGGAAAGAATGAGTCTAATATCAAGCCTGTACAGACAGCTAATA TCACTGCAGGCTTTCCTGTGGTTTGTCAGAAAGATAAG---CCAGTTGATTATGCCAAATGTAGTATCAAAGGAGGCTCT AGGTTTTGTCTATCATCTCAGTTCAGA---GGCAACGAAACTGGACTCATTACTCCAAATAAACATGGACTTTCACAAAA CCCATATCATATACCACCACTTTTTCCCATCAAGTCATTTGTTAAAACTAAATGTAAGAAAAAC---CTGCTAGAGGAAA ACTCTGAGGAACATTCAATGTCACCTGAAAGAGAAATGGGAAACGAGAAC---ATTCCAAGTACAGTGAGCATAATTAGC CGTAATAACATTAGAGAAAATGTTTTTAAAGAAGCCAGCTCAAGCAATATTAATGAAGTAGGTTCCAGTACTAATGAAGT GGGCTCCAGTATTAATGAAGTAGGTTCCAGT---------------------GATGAAAACATTCAAGCAGAACTAGGTA GAAGCAGAGGGCCAAAATTGAATGCTATGCTTAGATTAGGGGTTTTGCAACCTGAGGTCTATAAACAAAGTTTT---CCT GGAAGTAATGGTAAGCATCCTGAAATAAAAAAGCAAGAATATGAAGAA---GTACTTCAGACTGTTAATACAGACTTCTC TCCATGTCTGATTTCAGATAACCTAGAACAG---CCTATGAGAAGTAGTCATGCATCTCAGGTTTGTTCTGAGACACCTA ATGACCTGTTAGATGATGGTGAAATAAAGGAAGATACTAGTTTTGCTGAAAATGACATTAAGGAAAGTTCTGCTGTTTTT AGCAAAAGCGTCCAGAGAGGAGAGCTTAGCAGGAGTCCTAGCCCTTTCACCCAT---ACACATTTGGCTCAGGGTTACCG AAGAGGGGCCAAGAAATTAGAGTCCTCAGAAGAGAACTTATCTAGTGAG >Gorilla TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAACAAACAGCCTGGCTTAGCAAGGAGCCAACATAACAGATGGGCTGGAAGTAAGGAAA CATGTAATGAT---AGGCGGACTCCCAGCACAGAAAAAAAGGTAGATCTGAATGCTGATCCCCTGTGTGAGAGAAACGAA TGGAATAAGCAGAAACTGCCATGCTCAGAGAATCCTAGAGAT---ACTGAAGAT---GTTCCTTGGATAACACTAAATAG CAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGAACTGTTAGGTTCTGATGACTCACATGATGGGGGGTCTG AATCAAATGCCAAAGTAGCTGATGTATTGGACGTTCTAAAT------GAGGTAGATGAATATTCTGGTTCTTCAGAGAAA ATAGACTTACTGGCCAGTGATCCTCATGAGGCTTTAATATGTAAAAGTGAAAGAGTTCACTCCAAATCAGTAGAGAGTAA T---ATTGAAGACAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCCAGCTTAAGCCATGTAACTGAAAATC TAATTATAGGAGCATTTGTTACTGAGCCACAGATAATACAA--------------------------------------- ---------------------GAGCGTCCCCTCACAAATAAATTAAAGCGTAAAAGGAGAGCTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGCAGATTTGGCAGTT---CAAAAGACTCCTGAAATGATAAATCAGGGAACTAACCAAATGG AGCAGAAT---------GGTCAAGTGATGAATATTACTAATAGTGGTCATGAGAATAAAACAAAAGGTGATTCT---ATT CAGAATGAGAAAAATCCTAACCCAATAGAA------TCACTAGAAAAAGAATCTGCTTTCAAAACGAAAGCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTCGAATTAAATATCCACAATTCAAAAGCGCCTAAAAAGAATAGGCTGAGGAGGA AGTCTTCTACCAGGCATATTCATGCGCTTGAACTAGTAGTCAGTAGAAATCTAAGCCCACCTAATTGTACTGAATTGCAA ATTGATAGTTGTTCTAGCAGTGAAGAG---ATAAAGAAAAAA---AAGTACAACCAAATGCCAGTCAGGCACAGCAGAAA CCTACAGCTCATGGAAGATAAAGAACCTGCAACTGGAGCCAAGAAGAGTAACAAGCCAAATGAACAGACAAGTAAAAGAC ATGACAGCGATACTTTCCCAGAGCTGAAGTTAACAAATGCACCTGGTTCTTTTACTAACTGTTCAAATACCAGTGAACTT AAAGAATTTGTCAATCCTAGCCTTCCAAGAGAAGAAAAAGAAGAGAAA---CTAGAAACAGTTAAAGTGTCTAATAATGC CGAAGACCCCAAAGATCTCATGTTAAGTGGAGAAAGG---GTTTTGCAA---ACTGAAAGATCTGTAGAGAGTAGCAGTA TTTCATTGGTACCTGGTACTGATTATGGCACTCAGGAAAGTATCTCGTTACTGGAAGTTAGCACTCTAGGG---AAGGCA AAA---ACAGAACCAAATAAATGTGTGAGTCAGTGTGCAGCATTTGAAAACCCCAAGGGACTAATTCATGGTTGT---TC CAAAGATACTAGAAATGACACAGAAGGCTTTAAGTATCCATTGGGACATGAAGTTAAC---CACAGTCGGGAAACAAGCA TAGAAATGGAAGAAAGTGAACTTGATGCTCAGTATTTGCAGAATACATTCAAGGTTTCAAAGCGCCAGTCATTTGCTCTG TTTTCAAATCCAGGAAATCCAGAAGAGGAATGTGCAACATTCTCTGCCCACTCTAGGTCCTTAAAGAAACAAAGTCCAAA AGTCACTTTTGAATGTGAACAAAAGGAAGAAAATCAAGGAAAGAATGAGTCTAATATCAAGCCTGTACAGACAGTTAATA TCACTGCAGGCTTTCCTGTGGTTTGTCAGAAAGATAAG---CCAGTTGATTATGCCAAATGTAGTATCAAAGGAGGCTCT AGGTTTTGTCTATCATCTCAGTTCAGA---GGCAACGAAACTGGACTCATTACTCCAAATAAACATGGACTTTTACAAAA CCCATATCATATACCACCACTTTTTCCCATCAAGTCATTTGTTAAAACTAAATGTAAGAAAAAC---CTGCTAGAGGAAA ACTTTGAGGAACATTCAATGTCACCTGAAAGAGAAATGGGAAATGAGAAC---ATTCCAAGTACAGTGAGCACAATTAGC CGTAATAACATTAGAGAAAATGTTTTTAAAGAAGCCAGCTCAAGCAATATTAATGAAGTAGGTTCCAGTACTAATGAAGT GGGCTCCAGTATTAATGAAGTAGGTTCCAGT---------------------GATGAAAACATTCAAGCAGAACTAGGTA GAAACAGAGGGCCAAAATTGAATGCTATGCTTAGATTAGGGGTTTTGCAACCTGAGGTCTATAAACAAAGTCTT---CCT GGAAGTAATTGTAAGCATCCTGAAATAAAAAAGCAAGAATATGAAGAA---GTAGTTCAGACTGTTAATACAGATTTCTC TCCATGTCTGATTTCAGATAACTTAGAACAG---CCTATGGGAAGTAGTCATGCATCTCAGGTTTGTTCTGAGACACCTG ATGACCTGTTAGATGATGGTGAAATAAAGGAAGATACTAGTTTTGCTAAAAATGACATTAAGGAAAGTTCTGCTGTTTTT AGCAAAAGCGTCCAGAGAGGAGAGCTTAGCAGGAGTCCTAGCCCTTTCACCCAT---ACACATTTGGCTCAGGGTTACCG AAGAGGGGCCAAGAAATTAGAGTCCTCAGAAGAGAACTTATCTAGTGAG >Human TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAACATAACAGATGGGCTGGAAGTAAGGAAA CATGTAATGAT---AGGCGGACTCCCAGCACAGAAAAAAAGGTAGATCTGAATGCTGATCCCCTGTGTGAGAGAAAAGAA TGGAATAAGCAGAAACTGCCATGCTCAGAGAATCCTAGAGAT---ACTGAAGAT---GTTCCTTGGATAACACTAAATAG CAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGAACTGTTAGGTTCTGATGACTCACATGATGGGGAGTCTG AATCAAATGCCAAAGTAGCTGATGTATTGGACGTTCTAAAT------GAGGTAGATGAATATTCTGGTTCTTCAGAGAAA ATAGACTTACTGGCCAGTGATCCTCATGAGGCTTTAATATGTAAAAGTGAAAGAGTTCACTCCAAATCAGTAGAGAGTAA T---ATTGAAGACAAAATATTTGGGAAAACCTATCGGAAGAAGGCAAGCCTCCCCAACTTAAGCCATGTAACTGAAAATC TAATTATAGGAGCATTTGTTACTGAGCCACAGATAATACAA--------------------------------------- ---------------------GAGCGTCCCCTCACAAATAAATTAAAGCGTAAAAGGAGACCTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGCAGATTTGGCAGTT---CAAAAGACTCCTGAAATGATAAATCAGGGAACTAACCAAACGG AGCAGAAT---------GGTCAAGTGATGAATATTACTAATAGTGGTCATGAGAATAAAACAAAAGGTGATTCT---ATT CAGAATGAGAAAAATCCTAACCCAATAGAA------TCACTCGAAAAAGAATCTGCTTTCAAAACGAAAGCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTCGAATTAAATATCCACAATTCAAAAGCACCTAAAAAGAATAGGCTGAGGAGGA AGTCTTCTACCAGGCATATTCATGCGCTTGAACTAGTAGTCAGTAGAAATCTAAGCCCACCTAATTGTACTGAATTGCAA ATTGATAGTTGTTCTAGCAGTGAAGAG---ATAAAGAAAAAA---AAGTACAACCAAATGCCAGTCAGGCACAGCAGAAA CCTACAACTCATGGAAGGTAAAGAACCTGCAACTGGAGCCAAGAAGAGTAACAAGCCAAATGAACAGACAAGTAAAAGAC ATGACAGCGATACTTTCCCAGAGCTGAAGTTAACAAATGCACCTGGTTCTTTTACTAAGTGTTCAAATACCAGTGAACTT AAAGAATTTGTCAATCCTAGCCTTCCAAGAGAAGAAAAAGAAGAGAAA---CTAGAAACAGTTAAAGTGTCTAATAATGC TGAAGACCCCAAAGATCTCATGTTAAGTGGAGAAAGG---GTTTTGCAA---ACTGAAAGATCTGTAGAGAGTAGCAGTA TTTCATTGGTACCTGGTACTGATTATGGCACTCAGGAAAGTATCTCGTTACTGGAAGTTAGCACTCTAGGG---AAGGCA AAA---ACAGAACCAAATAAATGTGTGAGTCAGTGTGCAGCATTTGAAAACCCCAAGGGACTAATTCATGGTTGT---TC CAAAGATAATAGAAATGACACAGAAGGCTTTAAGTATCCATTGGGACATGAAGTTAAC---CACAGTCGGGAAACAAGCA TAGAAATGGAAGAAAGTGAACTTGATGCTCAGTATTTGCAGAATACATTCAAGGTTTCAAAGCGCCAGTCATTTGCTCCG TTTTCAAATCCAGGAAATGCAGAAGAGGAATGTGCAACATTCTCTGCCCACTCTGGGTCCTTAAAGAAACAAAGTCCAAA AGTCACTTTTGAATGTGAACAAAAGGAAGAAAATCAAGGAAAGAATGAGTCTAATATCAAGCCTGTACAGACAGTTAATA TCACTGCAGGCTTTCCTGTGGTTGGTCAGAAAGATAAG---CCAGTTGATAATGCCAAATGTAGTATCAAAGGAGGCTCT AGGTTTTGTCTATCATCTCAGTTCAGA---GGCAACGAAACTGGACTCATTACTCCAAATAAACATGGACTTTTACAAAA CCCATATCGTATACCACCACTTTTTCCCATCAAGTCATTTGTTAAAACTAAATGTAAGAAAAAT---CTGCTAGAGGAAA ACTTTGAGGAACATTCAATGTCACCTGAAAGAGAAATGGGAAATGAGAAC---ATTCCAAGTACAGTGAGCACAATTAGC CGTAATAACATTAGAGAAAATGTTTTTAAAGAAGCCAGCTCAAGCAATATTAATGAAGTAGGTTCCAGTACTAATGAAGT GGGCTCCAGTATTAATGAAATAGGTTCCAGT---------------------GATGAAAACATTCAAGCAGAACTAGGTA GAAACAGAGGGCCAAAATTGAATGCTATGCTTAGATTAGGGGTTTTGCAACCTGAGGTCTATAAACAAAGTCTT---CCT GGAAGTAATTGTAAGCATCCTGAAATAAAAAAGCAAGAATATGAAGAA---GTAGTTCAGACTGTTAATACAGATTTCTC TCCATATCTGATTTCAGATAACTTAGAACAG---CCTATGGGAAGTAGTCATGCATCTCAGGTTTGTTCTGAGACACCTG ATGACCTGTTAGATGATGGTGAAATAAAGGAAGATACTAGTTTTGCTGAAAATGACATTAAGGAAAGTTCTGCTGTTTTT AGCAAAAGCGTCCAGAAAGGAGAGCTTAGCAGGAGTCCTAGCCCTTTCACCCAT---ACACATTTGGCTCAGGGTTACCG AAGAGGGGCCAAGAAATTAGAGTCCTCAGAAGAGAACTTATCTAGTGAG >Chimpanzee TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAACATAACAGATGGGCTGGAAGTAAGGAAA CATGTAATGAT---AGGCGGACTCCCAGCACAGAAAAAAAGGTAGATCTGAATGCTGATCCCCTGTGTGAGAGAAAAGAA TGGAATAAGCAGAAACTGCCATGCTCAGAGAATCCTAGAGAT---ACTGAAGAT---GTTCCTTGGATAACACTAAATAG CAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGAACTGTTAGGTTCTGATGACTCACATGATGGGGGGTCTG AATCAAATGCCAAAGTAGCTGATGTATTGGACGTTCTAAAT------GAGGTAGATGAATATTCTGGTTCTTCAGAGAAA ATAGACTTACTGGCCAGCGATCCTCATGAGGCTTTAATATGTAAAAGTGAAAGAGTTCACTCCAAATCAGTAGAGAGTAA T---ACTGAAGACAAAATATTTGGGAAAACCTATCGGAGGAAGGCAAGCCTCCCCAACTTAAGCCATGTAACTGAAAATC TAATTATAGGAGCATTTGTTACTGAGCCACAGATAATACAA--------------------------------------- ---------------------GAGCGTCCCCTCACAAATAAATTAAAGCGTAAAAGGAGAGCTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGCAGATTTGGCAGTT---CAAAAGACTCCTGAAATGATAAATCAGGGAACTAACCAAATGG AGCAGAAT---------GGTCAAGTGATGAATATTACTAATAGTGGTCATGAGAATAAAACAAAAGGTGATTCT---ATT CAGAATGAGAAAAATCCTAACCCAATAGAA------TCACTCGAAAAAGAATCTGCTTTCAAAACGAAAGCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTCGAATTAAATATCCACAATTCAAAAGCACCTAAAAAGAATAGGCTGAGGAGGA AGTCTTCTACCAGGCATATTCATGCGCTTGAACTAGTAGTCAGTAGAAATCTAAGCCCACCTAATTGTACTGAATTGCAA ATTGATAGTTGTTCTAGCAGTGAAGAG---ATAAAGAAAAAA---AAGTACAACCAAATGCCAGTCAGGCACAGCAGAAA CCTACAACTCATGGAAGATAAAGAACCTGCAACTGGAGTCAAGAAGAGTAACAAGCCAAATGAACAGACAAGTAAAAGAC ATGACAGCGATACTTTCCCAGAGCTGAAGTTAACAAATGCACCTGGTTCTTTTACTAACTGTTCAAATACCAGTGAACTT AAAGAATTTGTCAATCCTAGCCTTCCAAGAGAAGAAGAAGAAGAGAAA---CTAGAAACAGTTAAAGTGTCTAATAATGC CGAAGACCCCAAAGATCTCATGTTAAGTGGAGAAAGG---GTTTTGCAA---ACTGAAAGATCTGTAGAGAGTAGCAGTA TTTCATTGGTACCTGGTACTGATTATGGCACTCAGGAAAGTATCTCGTTACTGGAAGTTAGCACTCTAGGG---AAGGCA AAA---ACAGAACCAAATAAATGTGTGAGTCAGTGTGCAGCATTTGAAAACCCCAAGGGACTAATTCATGGTTGT---TC CAAAGATACTAGAAATGACACAGAAGGCTTTAAGTATCCATTGGGACATGAAGTTAAC---CACAGTCGGGAAACAAGCA TAGAAATGGAAGAAAGTGAACTTGATGCTCAGTATTTGCAGAATACATTCAAGGTTTCAAAGCGCCAGTCATTTGCTCTG TTTTCAAATCCAGGAAATCCAGAAGAGGAATGTGCAACATTCTCTGCCCACTGTAGGTCCTTAAAGAAACAAAGTCCAAA AGTCACTTTTGAACGTGAACAAAAGGAACAAAATCAAGGAAAGAATGAGTCTAATATCAAGCCTGTACAGACAGTTAATA TCACTGCAGGCTTTCCTGTGGTTTGTCAGAAAGATAAG---CCAGTTGATTATGCCAAATGTAGTATCAAAGGAGGCTCT AGGTTTTGTCTATCATCTCAGTTCAGA---GGCAACGAAACTGGACTCATTACTCCAAATAAACATGGACTTTTACAAAA CCCATATCATATACCACCACTTTTTCCCATCAAGTCATTTGTTAAAACTAAATGTAAGAAAAAC---CTGCTAGAGGAAA ACTTTGAGGAACATTCAATGTCACCTGAAAGAGAAATGGGAAATGAGAAC---ATTCCAAGTACAGTGAGCACAATTAGC CGTAATAACATTAGAGAAAATGTTTTTAAAGAAGCCAGCTCAAGCAATATTAATGAAGTAGGTTCCAGTACTAATGAAGT GGGCTCCAGTATTAATGAAGTAGGTTCCAGT---------------------GATGAAAACATTCAAGCAGAACTAGGTA GAAACAGAGGGCCAAAATTGAATGCTATGCTTAGATTAGGGGTTTTGCAACCTGAGGTCTATAAACAAAGTCTT---CCT GAAAGTAATTGTAAGCATCCTGAAATAAAAAAGCAAGAATATGAAGAA---GTAGTTCAGACTGTTAATACAGATTTCTC TCCATGTCTGATTTCAGATAACTTAGAACAG---CCTATGGGAAGTAGTCATGCATCTCAGGTTTGTTCTGAGACACCTG ATGACCTGTTAGATGATGGTGAAATAAAGGAAGATACTAGTTTTGCTGAAAATGACATTAAGGAAAGTTCTGCTGTTTTT AGCAAAAGCGTCCAGAGAGGAGAGCTTAGCAGGAGTCCTAGCCCTTTCACCCAT---ACACATTTGGCTCAGGGTTACCG AAGAGGGGCCAAGAAATTAGAGTCCTCAGAAGAGAACTTATCTAGTGAG >Jackrabbit -------------------------------------------------------------------------------- -AAGGCTGAATTCTGTAATAAGAGCAAACAGCCTGGCTTAGCAAGAAGCCAACAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCCAGCACAGAGAAAAAGGTAGTTCTGAATGTTGACTGCCTGTATGGGAGAAAACAA CAGGATAAGCAGAAACCTCCATGCCCTGAGACCTCTGGAGAT---AACCAAGAT---GTTTCTTGGATAACAGTAAATAG CAGCATTCGGAAAGTTAACGAGTGGTTCTCCAGAAGTAATGAAATGTTAACTCCTGATGACTCACTTGACCGGCGGTCTG AATCAAATGCCAAAGTGGCTGGTGCATTAGAAGTCCCAAAG------GAGGTAGATGGATATTCTGGTTCTACAGAGAAA ATAGACTTACTGGCCAGTGATTCCCATAATGCTTTAATATGTGAAAGCAAAAGAGTCCATTCCAAACCAGTAGAGAATAA T---ATCAAAGATAAAATATTTGGGAAAACCTACCACAGGAAGACAAGCCTCCCTAACTTGAGCCACATAACTGAAGATC TAACTATAGGAGCATTTGCTGCGGAACCACTGGTA--------------------------------------------- ---------------------CCATGTCCCCCCGCAAATAAATTAAAGCGTAAAAGAAGAACTTCTTCAGGCCTTCAACC TGAAGATTTTATCAAGAAGGTAGATTTGGCAGTTGTTCCAAAAACCACTGCACAGATAAATCAGGGAACTGATCAAACGG TGGACAGT---------GATCAGGTGATGAATATTACTAATTGTGGTAATGAGAATGAAACAGAAGGTGACTAT---ATT CAGAAAGAGACAAATGCTAACCCAACAGAA------TCCCTAGAAAAAGACTCTTCCTTCAGAACTAAAGTTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTAGAATTAAATGTCCATAATTCAAAAAAACCCAAGAAGAATAGGCTGAGGAGGA AGTCCTCTACCAGGCGTGTTCATGCACTTGAACTAGTAGTCAATAAGAAACCGAGCCCACCTAATCATGCTGAACTACAA ATTGACAGTTGTACTAGCAGTGAAGAA---ATG------------AATTTTGACCAAATACCAGTCAGTCACAGCAGACA GGCTCAAGTCATAGAAGATACAGAACCTCCAACTGGAGCTAGGAAG---AACAAGCCAAGTGAACAAATAAGTAAAAGAC ATGCCAGTGATGTTTTCCCAGAAGTCAAATTAACAAACATACCTGGTGTTTTTACAAACTGTTCAAGTTCTAATAAACTT CAAGAATCTGTCGATCCTAGCCTTCAAAGAAGGGAAATAGAAGAGAAC---CTAGACACAGTTCAAGTGCCTAACAGTGC CATAGACCCCAAAGATCTCCTGTTATGTGGAGAAAGG---GGCTTGCAA---ACTGAAAGGTCTGCGGAGAGTACCAGTA TTTCACTGGTACCTGATACTGAATATGGTACCCAGGACAGCATCTCATTACTGGGCGCTAACACCCTTGGG---AAGGCA AAA---ACAGCAGCAAATGGACATGTGAGTGAGAGCACAACAATTGGAAATCCCAAGGAACTTAGCCATGATTGT---TT GAAAGATACTGGAAATGACCCAGACAACTGTAAGGATCCACTGAGAAGTGAAGTTGAC---------CAAGAGACAAGCG TAGAAATGGAAGAGAGTGAGTTTGATACTCAGTATTTACAGAATACATTCATGGGTTCAAAGCGTCGTTCATTTGCTCTG TGTTCAAAACCAGGAGATCCAGAAAAGGAATGTGCAGCAGTCTGTACCCGCTCCAACTCCTCAAGGAAACAAAGTCCAGA AGTCACTCTTGAACGTGAACAAAAAGAA---AGTCAGAGAAAGGAAGAGTGGAAAATCAGTCATGTCCAGGCAGCTGATA GCACTGTGGGCTTTCCTGTGGTGTGTCAGAAAGAAAAG---GCAGGTGATTGTGCCAAATGGAGCACTAAAGAGATCTCT AGGCTTTGTCTGTCATCTCAGTCCAAA---GGCAGTGAAACTGAGCTCATTGCTGTAAGTAAACATGGGATGTCACAAAA CCCATATCATATACCACCAATTTCTCCCATCAAGACATCTGTTAAAGCCACACGCCAGGTACAC---CTGTCAGGGGAAA GGTCTGAGGAGCATTCCGTGTCATCTGAAAGAGCAGTGGGAAGCGAGAGCATCATTCAAAGCACAGTGAGCACAATTAGC CAAGAGTACATTAGAGAAAGTGCTTTGAAAGGATTCAGCTCAAGCAGTATTAATGAAGGGGGCTCTAGTGCTAACGAAGT ATGCTCCAGTGTGAATGAAGTAGGATCCAGT---------------------GGTGAAAACATGCAAGCACAACCAGGCA GAAGCAGAGCACCTGAGTTAAATGCTGTGCTGAGAATAGGTCTTCTGCAGCCTGAAGTCTCTGAGCAAAGCCTT---CCT ATAAGTAATTCTGAACTTCCCAAACTACAAAGGCAAGGAGAAAACGAAGGAGTAGTTCAGGCTGTGAATAGAGATTTCTC TTCGTATCTGGTTCCTGATAGCCAAGAGCAG---TCTATGGGAGGAAGGCATGCTTCTCAGATTTGTTCTGAGACACCTG ATGACCTGTTAGATATTTATGAAATAAAGGAAAATACCAGCTTTGCTGAGAGCGGCATTAAGGAAAGATCTGCTGTGTTT AGTAAAAGTGTTCAGAGGGGAGAGTGCAGTAGAACCCCTAGCCCTTCAGGCCAT---GCATGTTTGGCTCAGAGTCA--- ------------------------------------------------- >FlyingSqu TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAGCAGAGCAGATGGGCTAAAAGTAAGGAAA CCTGTAATGAT---AGGCAAATTCCCAGCTCAGAGAAAAAGGTAGATTTGAATGCTGATCCCCAATATGAGAAAAAAGAA CCAAGTAAGCAGAAACATCCATGCTCTGAGAATTCCAGAGAT---ACCCAAGAT---GTTCCTTGGATAACACTAAATAG CAGCATTCGGAAAGTTAACGAGTGGTTTTCCAGAAGTGACGAAATGTTAACTTCTGATGACTCAGATGATGGGGGTTCTG AATCAAATGCTGAAATAGCTGGTATATTAGAAATTCCAAAT------GAAGTAGATGGATTTTCTGGTTCTTCGGAGAAA ATAGACTTGTTGGCCACTGATCCGCATAATGCTTTAATTTCTAAATGTAAAAGAGTCTGCTCCAAAGCAGTCAAGAGTAA T---ATTGAAGATAAAATATTTGGGAAAACCTATCAGAGGAAGGCAAGCCTCCCTAACTTGAGCCATATAACTGAAAATC TAATTATAGGAGCATTTGCCAGAGAACCACAAATAACACAAGAGCTTGCCAGAGAACCACAAATAACACAACAGCTTGCC AGAGAACCACAAATAACACAAGAGCGTCCCCTCACAAATAAATTAAGACGTAAAAGGAGAACTACATCATGCCTTCATCC TGAGGACTTTATCAAGAAAACAGATTTGGCAATTGTTCAAAAGACTCCTGAAAAGATAAATCAGGGAACTGACCAAATGG AACACAAT---------GATCAAGTAATGAATATTACTAATAGTGGTCAAGAGAATGAAACAAAAGTTGATTAT---GTT CAGAAAGAGAAAAATGCTAACCCAGTTGAA------TCATTGGAAAAAGAGTCTGCTTTCAGAACTAAAGCTGAACCTAT AAGCAGTAGTATAAGCAACATGGAACTAGAATTAAATATCCACAATTCAAAAGCACCTAAGAAAAATAGGCTGAGGAGGA AGTCTTCTACTAGGTACATTCATGTGCTTGAACCAGTAGTTAATAGAAATACAAGTCCACCTCATCACACTGAATTGCAA ATTGATAGTTGTACTAGTAGTGAAGAA---ATAAAGACAAGA---AATTCCAACCAAATGTCAGTCAGGCATGGCAAAAA GCTTCAGTTCATGGAAGATGCAGAACCTGCAACTGATGTCAGAAAAAGTAACAAGCCAAATGAACAAGTAAATAAGAGAC ATACCAATGATGCTTTCCCAGGACTGAAGTTAACAGGCATATCTGGTATTTTTACTAACTGCTCAAGTTCTAGTAAAGTT GAAGAATTTATCAATCCTAACCTTCAGAAAGAAGGAACAGAAGAGAAC---ATAGAAATAATTCAAGTGTCTGATAATAC CCAAGACCCCAAAGATACGGTGTTAAGTGGAGAAAGG---GTTTTGCAA---ACTGAGAGATCTGTAGAGAGTACCAGTA TTTCATTGGTACCTGATACTGATTATGGCACTCAGGACAGTATCTCATTACTGGAAGCTAACACCTTTGGA---AAAGCA AGA---ACAGCATCAAATCAACATGTTACTCAGTATGTGGCAATTGAAAATCCCAAAGAATTTGTCCATGGTCAT---TC TAAAGATACTAAAAATGACCCAGAGGGTTTCAAGGATTCATTGAGATGTGAAGTTAAC---CACATTCAAGAGACAAATG TAGAAATGGAAGAAAGTGAACTTGATACTCAGTCTTTAGAGAATACATTCCAAGTTTCAAAGCGTCAGTCATTTGCTCTG TTTTCAAATCCAGGAAATCTAGAAAAGGAATGTGCAGCCAACTATACCTCTTCCAAGTCCTTACGGAAACAAAGCCCAGA CATGACTCTTGAATGTGAGCAAGAAGAAGAAAATTGGGGAAAGAAAGAGTCTAAAATTAGGCATGTACAGGCAATTAATG CTACT------------ATGGTTTGTCAGAAAAGTAAG---CCAGATGATGATGCCCAATGTAGTGTTACAGAAGTCTCT AGAATTTTTCCATCATTTCAGTTCAGA---GACAATCTAACTAAACTCATAACTGCAGATAAACATGGAATTTCACAAAA CCCATATCATATGCCATCCATTTCTCCCAGCAGGTCATCTGTTAACACTAAATGTAGGAGAAAC---CTATCAGAAGAAA AGTTTGAGAAAGATTCAAGGTCACCTAAAGAAGCGGTGGGATATAAGAGAATCATTCAAAGTACAGTGAGCACAATTAGC CAAAATAACATTAGACAAAGTGCCTTTAAAGAAGCGAACTCAGGCAGTATTAATGAAGTAGGCTCTAGTACTAATGAAGT AGGCTCCAGTATTAATGAAGTAGGTTCCAGT---------------------GGTGAAAACATTCAAGCAGAACTAGGTA GAAACAGAGGACCCAAATTAAATGCTGTGCTTAGATTAGGTCTTATGCAACCTGAAGCCTGTAAACAAAATCTT------ CTAAGTAATTGTAAATACCCTGAAATAAAAAGACAAGGAGAAGATGAA---GTAGTTCAAGTTGTTAATGCAGATTTCTC TCCATGTCTAATTTCAGATGACTTAGAACAA---CCTATGGGAAATAGTCATGTCACTCAGGTTTGTTCTGAGACTCCTG ATGACCTGTTAGATGATGATGAAATACAGGAAAATACCAGCTTTGCTGAAGGTGGTATTAAGGAAAGATCTGCTGTTTTT AGTAAGAGTGTCCAAAGAGGAGAGTTTAGCAGGAGCCCGAGTCCTTTATCCCAT---ACGTCTTTGGCTCGGAGTCATCA AAAAGGGGCCAGGAAATTAGAGTCCTCAGAAGAGAGCATCTGTAGTGAG >OldWorld -------------------------------------------------------------------------------- ----------------------------------------------AGCCAACAGAGCAGGTGGGCTGAGAGCAAGGAGA GGTGCCATGAC---AGGCAGGCTCCTGGCACAGAGCAGAAGGTAGAGCTGACTGCTGAGCCCCTCCACGAGAGAAAAAGA CGGAAAAAGCAGAACCCTCCGAGCTCCGAGGCTCATGGAGGG---ACCCAGGAT---GTTCCTTGGATCACACTAAATAG CAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGACAAAGCAGTGACTTCTGACAGCACCTGTGACAGGGAGTCCA AGTCAGATGCTGAAGAAGCTGGTGTGGCAGAAGATCCAAAA------GGCCTAGAT---------GGCTCTTCAGAGAAA GTAGGCTTGCTGACCAGCAGTCCTCAAAAAGCTATAATCTGTGCCAGGGAGAGGGTCTGCTCCAAAGCACTGAAGAGTGA C---ATGGAAGATAAAGTATTTGGGAAAACCTATCAGAGGAGGGTGAGCCTCCGCAGCTCAAGCCACGGAGCTGAAAGTC TGACCGTGGGAGCGTTTGTTAGAGAGCCGCAGCTGACACTG--------------------------------------- ---------------------GAGCGCTCCTTCACAAATAAAATAAAGCGCAAGAGGAGAACCACATCGTGCCTTCATCC TGAGGACTTTGTCAAGAAAGCAGATTTGACAGTGGCTCAAAAGACTCCTGAAAAGGTAAATCAGGGAACGAAGCAAATGG AGGAGAGT---------AGTCAAGTGACAAATACTACTAATAACAGTCATGAGAATGAGACAAAAATGGGCAAT---GTT CAG------AGAAACCCTAACCCAGTACTA------TCAGTGGAAAAAGAGTCTGCTTCTGGTACTAACGCAGAGCCCTC GAGCAGCAGCATAAACAACAGGGAACTAGAATTAAACACCCCTCTTGCAAAAGAACCTAAGGAAGACAGGCTGAGGGGGA CGTCCTCAAGCAGACACAGACCT------------------------AATCCACACCTGCTGGATCACACAGAGCTGCAA AGTGGCAATTCTATCAGCAGTGAAGAA---ATAAAGGAAAAA---AGCTCCCCCCAAATGCCCATCAGGCACAGCAGGAC GCTGCACCTCACAGGGGCTGTGGAAGCTTCTATTGGAGCCAGGGAGAGTAAGAAGCCAGCTGGACAAGTAAGGGAGAGAC ATGCCGGGGACTCTTTCCTAGAACCAAGATTAGCAAGACTACCTGCT---TTTACTAACAGTTCAAGCCCTGATAACCTT AAAGAATTTGTCAACCTTAGTGCACAGACAGAAGAGATGGAAGAGAAC---CCAGAAACAGTACAAGTGTCCGAAAGTAC CAGAGACTCCAAAGGTCCTGTGTTAAGTGGGGAAAAG---GGAGTGCAA---ACCGAGAGGTCTATGGAGAGCACTAGCA TTTCACTAGTCCCTGACACTGACTGTGGCACTCAGGACAGTGTCTCCTTACTGGAAGCCGACAGCCTCAGG---AAGGCA CGG---AGAGCATCGCATCAGTGTATGGCTCAATATGTGGCGGTTGCGAAGCCCAAGGAACTTCTGCCTGCTTGT---TC TGAAGACACTGGAAACGGCACAGACAGCTTAAATGATCCATTGAGATGTGGAGGGAGC---CACATCCAGGAGGCAAATA TAGAAATGGAAGATAGTGAACTCGACACTCAGTATTTACAGAATACATTCCAGGCTTCAAAGCGTCAGTCATTTGCTCTC TTTTCAAATCCAGGAAACTCAAAAAAGGAATCAACAACAGTCTGTGCCCACTCTGAGTCCTTTAAGAAACAAAATCCAGA AGTCATTCCTGAATGTGAACAAACAGAAGAAAATTGGGGCAAGAAAGTGCCTAAAATTAGTTGTGTGCAAGAGAGCGCC- --------------CCTCTGGTTTCTCAGAGGGATCAG---CCAGGCACCAGCATCATATGTAGCGGCACAGGAGTCTCG AGGCTCTGTCTCTCGTCTTGGTTCACA---GGCAGCAAAACTGAACTCGTCACAGCTGACAAACATGGAATTTCACAAAA TCCATATCACATGCCATCAATTTCTCCCATCAGGCCATTTGTTAAAACTCCATGTAAGAAAACC---------------- -----------CGTTCCTCATCACCTGGAGAAGCCACAGGTAACCAGATCATCCTTCAGAGCACC--------------- ------------AGCCATCGCGCTTGCAGAGAAGCCAGCTTGGGCAGTGGGAACGAAGGGGGCTCCAGT----------- ----------------------------------------------------GGGGAGCACATTCAAGCAGAACCCAGTA GACACCAAGAGCCTGAACTA------------AGATTAGGTCTGACGCAGCCCGAAGTCTACCAGCAAAGTCTT---CCT GTAGGTGACTGTAGACATCCCGAAATACAAACACGAGGAGAAAATGGAGTGGTAGCTCAGGCTGTCCATGCAGATTTCTC TCCGTGTCTAATTTTAGATAACGTGGAACAG---CCTATGGGAAATAATCCTGCTTCTCAGATCTGTTCTGAGACGCCCG ATGACCTGTTAGATGATGAGAACAAAAAGGAAGATGCCAGCTTTGCCGAAGGTGGCATTAAGGAAACTTCTGCCATTTTT AGCAAGAGTGTCCAGACAAGACGATTCAGCAGGAGCCCCAGCCCTGTAACCAAT---ACCACTTTGGCTCAGGGTCACCG AAGAAGGGCGAGAAAACTCGAGTCTTCTGAGGAGAGCATGTCAAGTGAG >Mouse TGTGGCACAGATGCTCATGCCAGCTCATTACAGCCTGAGACCAGCAGTTTATTGCTCATTGAAGACAGAATGAATGCAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCATAGCAGTGAGCCAGCAGAGCAGATGGGCTGCAAGTAAAGGAA CATGTAACGAC---AGGCAGGTTCCCAGCACTGGGGAAAAGGTAGGTCCAAACGCTGACTCCCTTAGTGATAGAGAGAAG TGGACTCACCCGCAAAGTCTGTGCCCTGAGAATTCTGGAGCT---ACCACCGAT---GTTCCTTGGATAACACTAAATAG CAGCGTTCAGAAAGTTAATGAGTGGTTTTCCAGAACTGGTGAAATGTTAACTTCTGACAGCGCATCTGCCAGGAGGCACG AGTCAAATGCTGAAGCAGCTGTTGTGTTGGAAGTTTCAAAC------GAAGTGGATGGGGGTTTTAGTTCTTCAAGGAAA ACAGACTTAGTAACCCCCGACCCCCATCATACTTTAATGTGTAAAAGTGGAAGAGACTTCTCCAAACCAGTAGAGGATAA T---ATCAGTGATAAAATATTTGGGAAATCCTATCAGAGAAAGGGAAGCCGCCCTCACCTGAACCATGTGACTGAA---- --ATTATAGGCACATTTATTACAGAACCACAGATAACACAA--------------------------------------- ---------------------GAGCAGCCCTTCACAAATAAATTAAAACGTAAGAGA------AGTACATCCCTTCAACC TGAGGACTTCATCAAGAAAGCAGATTCAGCAGGTGTTCAAAGGACTCCTGACAACATAAATCAGGGAACTGACCTAATGG AGCCAAAT---------GAGCAAGCAGTGAGTACTACCAGTAACTGTCAGGAGAACAAAATAGCAGGTAGTAAT---CTC CAGAAAGAGAAAAGCGCTCATCCAACTGAA------TCATTGAGAAAGGAACCTGCTTCCACAGCAGGAGCCAAATCTAT AAGCAACAGTGTAAGTGATTTGGAGGTAGAATTAAACGTCCACAGTTCAAAAGCACCTAAGAAAAATAGGCTGAGGAGGA AGTCTTCTATCAGGTGTGCTCTTCCACTTGAACCA---ATCAGTAGAAATCCAAGCCCACCTACTTGTGCTGAGCTTCAA ATCGATAGTTGTGGTAGCAGTGAAGAA---ACAAAGAAAAAC---CATTCCAACCAACAGCCAGCCGGGCACCTTAGAGA GCCTCAACTCATCGAAGACACTGAACCTGCAGCGGATGCCAAGAAG---AACGAGCCAAATGAACACATAAGGAAGAGAC GTGCCAGCGATGCTTTCCCAGAAGAGAAATTAATGAACAAAGCTGGTTTATTAACTAGCTGTTCAAGTCCTAGAAAATCT CAAGGGCCTGTCAATCCCAGCCCTCAGAGAACAGGAACA---GAGCAA---CTTGAAACACGCCAAATGTCTGACAGTGC CAAAGAACTCGGGGATCGGGTCCTAGGAGGAGAGCCC---AGTGGCAAAACCACTGACCGATCTGAGGAGAGCACCAGCG TATCCTTGGTACCTGACACTGACTACGACACTCAGAACAGTGTCTCAGTCCTGGACGCTCACACTGTCAGA---TATGCA AGA---ACAGGATCCGCTCAGTGTATGACTCAGTTTGTAGCAAGCGAAAACCCCAAGGAACTCGTCCATGGC------TC TAACAATGCTGGGAGTGGCACAGAGGGTCTCAAGCCCCCCTTGAGACACGCGCTTAAC---CTCAGTCAGGAGAAA---G TAGAAATGGAAGACAGTGAACTTGATACTCAGTATTTGCAGAATACATTTCAAGTTTCAAAGCGTCAGTCATTTGCTTTA TTTTCAAAACCTAGAAGTCCCCAAAAGGACTGTGCT------------CACTCTGTGCCCTCAAAGGAACTGAGTCCAAA GGTGACAGCTAAAGGTAAACAAAAAGAA---CGTCAGGGACAGGAAGAATTTGAAATCAGTCACGTACAAGCAGTTGCGG CCACAGTGGGCTTACCTGTGCCCTGTCAAGAAGGTAAG---CTAGCTGCTGATACAATGTGT------GATAGAGGTTGT AGGCTTTGTCCATCATCTCATTACAGA---AGCGGGGAGAATGGACTCAGCGCCACAGGTAAATCAGGAATTTCACAAAA CTCACATTTTAAACAATCAGTTTCTCCCATCAGGTCATCTATAAAAACTGACAATAGGAAACCT---CTGACAGAGGGAC GATTTGAGAGACATACATCATCAACTGAGATGGCGGTGGGAAATGAGAACATTCTTCAGAGTACAGTGCACACAGTTAGC CTGAATAAC---AGAGGAAATGCTTGTCAAGAAGCCGGCTCGGGCAGTATTCATGAAGTATGTTCCACT----------- ----------------------------------------------------GGTGACTCCTTCCCAGGACAACTAGGTA GAAACAGAGGGCCTAAGGTGAACACTGTGCCTCCATTAGATAGTATGCAGCCTGGTGTCTGTCAGCAAAGTGTT---CCT GTAAGTGAT---AAGTATCTTGAAATAAAAAAGCAGGAG---------------GGTGAGGCTGTCTGTGCAGACTTCTC TCCATGTCTATTCTCAGACCATCTTGAGCAA---TCTATG---AGTGGTAAGGTTTTTCAGGTTTGCTCTGAGACACCTG ATGACCTGCTGGATGATGTTGAAATACAGGGACATACTAGCTTTGGTGAAGGTGACATAATGGAGAGATCTGCTGTCTTT AACGGAAGCATCCTGAGAAGGGAGTCCAGTAGGAGCCCTAGTCCTGTAACCCAT---GCATCGAAGTCTCAGAGTCTCCA CAGAGCGTCTAGGAAATTAGAATCGTCAGAAGAGAGCGACTCCACTGAG >Rat TGTGGCACAGATGCTCGTGCCAGCTCATTACAGCGTGGGACCCGCAGTTTATTGTTCACTGAGGACAGACTGGATGCAGA AAAGGCTGAATTCTGTGATAGAAGCAAACAGTCTGGCGCAGCAGTGAGCCAGCAGAGCAGATGGGCTGACAGTAAAGAAA CATGTAATGGC---AGGCCGGTTCCCCGCACTGAGGGAAAGGCAGATCCAAATGTGGATTCCCTCTGTGGTAGAAAGCAG TGGAATCATCCGAAAAGCCTGTGCCCTGAGAATTCTGGAGCT---ACCACTGAC---GTTCCTTGGATAACACTGAATAG CAGCATTCAGAAAGTGAATGAGTGGTTTTCCAGAACTGGTGAAATGTTAACTTCTGACAATGCATCTGACAGGAGGCCTG CGTCAAATGCAGAAGCTGCTGTTGTGTTAGAAGTTTCAAAT------GAAGTGGATGGATGTTTCAGTTCTTCAAAGAAA ATAGACTTAGTTGCCCCTGATCCCGATAATGCTGTAATGTGTACAAGTGGAAGAGACTTCTCCAAGCCAGTAGAGAATAT T---ATCAACGATAAAATATTTGGGAAAACCTATCAGAGAAAGGGAAGCCGCCCTCACTTGAACCATGTGACTGAA---- --ATTATAGGCACATTTACTACAGAACCACAGATTATACAA--------------------------------------- ---------------------GAGCAGCCCTTCACAAATAAATTAAAACGCAAAAGA------AGTACATGCCTTCATCC TGAGGACTTTATCAAGAAAGCAGATTTAACAGTTGTTCAAAGGATTTCTGAAAATTTAAATCAGGGAACTGACCAAATGG AGCCAAAT---------GACCAAGCAATGAGTATTACCAGTAACGGTCAGGAGAACAGAGCAACAGGTAATGAT---CTT CAGAGAGGGAGAAATGCTCATCCAATAGAA------TCATTGAGAAAGGAACCTGCTTTCACAGCTAAAGCCAAATCTAT AAGCAACAGTATAAGTGATTTGGAGGTAGAATTAAATGTTCACAGTTCAAAAGCACCTAAGAAAAATAGGCTGAGGAGGA AGTCT---ACCAGGTGTGTTCTTCCACTCGAACCA---ATCAGTAGAAATCCGAGCCCACCTACTTGTGCTGAACTTCAG ATCGAGAGTTGTGGTAGCAGTGAAGAA---ACAAAGAAAAAC---AATTCCAACCAAACCCCAGCCGGGCACATTAGAGA GCCTCAACTCATCGAAGACACAGAACCCGCAGCTGATGCCAAGAAG---AACGAGCCAAATGAACACATAAGGAAGAGAA GTGCCAGTGATGCGTTCCCAGAAGAGAAATTAATGAACAAAGCTGGTTTATTAACTAGCTGTTCAAGTCCTAGAAAGCCT CAAGGACCTGTCAATCCTAGCCCTGAGAGAAAAGGAATA---GAGCAA---CTTGAAATGTGCCAGATGCCTGATAATAA CAAAGAACTCGGGGATTTGGTCCTGGGAGGAGAGCCC---AGTGGGAAACCTACTGAACCATCTGAGGAGAGCACCAGTG TGTCCTTGGTACCCGACACAGACTACGACACCCAGAACAGTGTCTCAATACTGGAAGCGAACACTGTCAGA---TATGCA AGA---ACAGGATCAGTTCAGTGTATGACTCAGTTTGTCGCAAGTGAAAACCCCAAGGAACTTGTCCATGGT------TC TAACAATGCTGGAAGTGGCTCGGAGTGCTTCAAGCACCCATTGAGACATGAACTTAAC---CACAATCAAGAGACA---A TAGAAATGGAAGACAGTGAACTTGATACTCAGTATTTGCAGAATACATTTCAAGTTTCAAAGCGTCAGTCATTTGCTTTA TTTTCAAAACTTAGAAGTCCCCAAAAGGACTGTACTCTGGTAGGTGCCCGCTCTGTGCCCTCAAGGGAACCAAGTCCAAA GGTGACTTCTAGAGGTGAACAAAAAGAA---CGTCAGGGACAAGAAGAGTCTGAAATCAGTCATGTACAGGCAGTCACAG TCACAGTAGGCTTACCTGTGCCCTGTCAGGAAGGTAAG---CCAGGTGCTGTTACAATGTGT------GCTGATGTTTCT AGGCTTTGTCCGTCATCTCATTATAGA---AGCTGTGAGAATGGACTCAACACCACAGATAAATCTGGAATTTCACAAAA CTCACATTTTAGACAATCAGTTTCTCCCCTCAGGTCATCTATAAAAACTGACAATAGAAAAACT---CTGACAGAGGGNC GATTTGAGAAACAT---------ACTGAAAGGGGRATGGGAAATGAGACTGCTGTTCAAAGTACAATACACACAATTAGT CTAAATAAC---AGAGGAGATGCTTGTCTAGAAGCCAGCTCAGGCAGTGTTATTGAAGTACATTCCACT----------- ----------------------------------------------------GGTGAAAACGTCCAGGGGCAACTAGATA GAAACAGAGGGCCTAAGGTAAACACCGTGTCTCTATTAGATAGTACACAGCCTGGTGTCTCTAAGCAGAGTGCT---CCT GTAAGTGAT---AAGTATCTTGAAATA---AAGCAGGAG---------------AGTAAGGCTGTCAGTGCAGACTTCTC TCCATGTCTGTTCTCAGATCATCTTGAAAAA---CCTATGAGAAGTGATAAGACTTTTCAGGTTTGCTCTGAGACACCTG ATGACCTGTTGGATGATGTTGAAATACAGGAAAATGCTAGCTTCGGTGAAGGTGGCATAACGGAAAAGTCTGCTATTTTT AATGGAAGTGTCCTGAGAAGAGAGTCCAGTAGGAGCCCTAGCCCTGTAACCCAT---GCATCGAAGTCGCGGAGTCTCCA CAGAGGGTCTAGGAAATTAGAATTCTCAGAAGAGAGCGACTCCACTGAG >NineBande TGTGGCACAAATACTCATGCCAACTTATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGCGCCAACAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCCAGCATAGAGAAAAAGGTAGATGTGGATGCTGATCCCCTGTATGGGCGAAAAGAA CTGAATAAGCAGAAACCTCCATGCTCTGAGAGTCATAGAGAT---ACCCAAGAT---ATTCCTTGGATAATGCTGAATAG TAGCATTCAGAAAGTTAACGAGTGGTTTTCCAGAGGTGATGACATATTAACTTCTGATGACTCACACGATAGGGGGTCTG AATTAAATGCAGAAGTAGCTGGTGCATTGAAAGTTTCAAAA------GAAGTAGATGAATATTCTAGTTTTTCAGAGAAG ATAGACTTAATGGCCATTAATCCTCATGATACTTTACAATTTGCAAGTGAAAGAGTCCAATTGAAACCAGCAGAGAGTAA C---ATCAAAGATAAAATATTTGGGAAAACCTATCATAGGAAGGCAAGCCTCCCTAACTTGAGCCACATAACCCGAAACC TTTTTATAGGAGCTATTGCTGCAGAGCCCAAGATAACACAA--------------------------------------- ---------------------GAGCATTCCCTCCAAAATAAAATAAAGCGTAAAAGGAGAACTGCATCAGGCCTTCGTCC TGAGGATTTATCCAAGAAAGTAGATTTGACAGTTGTTCAAAAAACCCCTGAAAAGATAAATCAGGGAACTGACCAAATGG AGCAGAAT---------GATCCAGTGATGAATATTGCTAATAGTGGTCATGAGAATGAAACAAAAGGTGATTGT---GTT CAGAAAGAGAAAAATGCTAATCCGACAGAA------TCATTGGGAAAAGAATCTGCTTTCAGAACTAAAGGCGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTAGAATTAAATATTTTAAATTCAAAAGCATCTAAGAAGAATAGGCCGAAGAGGA TGTCCTCTACCAGGCATATTCATGCACTTGAACTAGTCGGCAGTAGAAATCCAAGCCCACCTAATCATACTGAACTACAA ATTGATAGTTGTTCTAGCATTGAAGAG---ATAGAGAAAATA---AATTCTAACCAAAAGCCAATCAGACACAACAGAAT GCTTCAACTCACGAAAGAAAAAGAAACCACAACTGGAGCCAAAAAGAACAATAAGCCAAATGAACAAATAAGTGAAAGAC ATGCCAGTGATGCTTTCCTAGAACTTAAA------AATGTAACTGATTTTCTTCCTAAATGTTCAAGTTCTGATAAACTT CAAAAATTT---AATTCTAGCCTGCAAGGAGAAGTAGCA---GAGAAC---CTAGAAACAATTCAAGTGTCTGATAGTAC CAGGGACCCTGAAGATCTGGTGGTAAGTGGAGAAAAG---TGTTTGCAA---ACTGAAAGATCTGCAGAGAGTACCGGTA TTTCAGTGGTACCTGATACTGATTATGGCACTCAAGACAGTATCTCATTACTGGAAGCTGACACCCTGGGG---AAGGCA AAA---ACAGCACTAAATCAACATGTGAGTCAGTATGTAGCAATTAGAAATGCCACTGAACTTTCCCATGGTTGT---TC TAAAGACACTAGAAATGACACTGAAGATTTTAAGGATTCATTGAGACATGAAGTTAAC---CACACTCAGGGGACAAATG TTGAAATAGAAGAGAGTGAACTTGATACTCAGTATTTGCAGAATACATTCAAGATTTCAAAGCGCCAGTCATTTGCTCTG TTTTCGAATCCA---------GAAAATGAATGTGCAACAGTCTGTGCCCACTCCAGGTTCTTAGGGAAACAAAGTCCAAA AGTCACCTTTGAATGTAGACATAAAGAAGAAAATCAGGGGAAGAAAGAGTCTAAAATCAAACATGTGCAGGTAATTCACA CAACTGCAGGCTTTCCTATAGTTTGTCAGAAAGATAAG---CCAGGTGATTATGCCAAAGGTAGCATTCAAGGAGTCTCT AGGCTTTGTCAGTCCTCTCAGGCCAGA---GGCAATGAATCTGAACTCATTAATTCAAATGAACATGAAATTTCACAAAA CCCAGATCAAATGCCATCACTTTCTCACATGAAGTCATCTGTTAAAACTAAATGTAAGGAAAAC---CTGTCAGAGGAAA AGTTTGAGGAACTTACAGTGTCACTTGAAAGAACAATGGTAAATGAGAACATCATTCAAAGTACAGTAAGCACAATTAGC CACAGTAACATTAGAGAAAACACTTTTAAAGAAGCCAGCTCAAGCAGTATTAATGAAGTAGGGTCCAGT----------- ----------------------------------------------------GATGAGAACATTCAAGCAGAAGTAGGTA GAAACAGAGCACCTAAATTAAATGCTATGCTCAGATTAGGTCTTATGCAACCTGAAGTCTATAAGCAAAGTCTT---CCT ATAACCAATTGTAAATATCCTGAAATAAAAAGTCAAGGAGAAAATGAAGAAGCAATTCGGGCTGTTGATATAGACTTCTC TCCATGTCTAATTTCAGATAACCTACAACTA---CCTATGGGAAATAGTTGTGCTTCCCAGATTTGTTCTGAGACACCTG ATGACTTGTTAGATGATGATGAAATAAAGGAAAATAACTGCTTTGCTGAAAGTGACATTAAGGAAAGATCTGCTATTTTT AGCAAAACTGTCCAGAAAAGAGAGTTCAGAAGGAGCCCTAGCCCTTTAGTCCAT---ACAAGTTTTGCTCAGGGTCACCA AAGAAAGCCCAGGAAATTAGACTCCTCAGAAGAGGACGTATCTAGTGAG >HairyArma TGTGGCACAAATACTCATGCCAACTTATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAGTGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGCGCCAACAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCCAACACAGAGAAAAAGGTAGATGTGGCTGCTGATTCCCTGTATGGGCGAAAAGAA CTGAATAAGCAGAAACTTCCATGCTCTGAGAGTCCTAGAGAT---ACCCAAGAT---ATTCCTTGGATAACGCTGAATAG TAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGACCTATTAACTTCTGATGACTCACACGATGGGGGGTCTG AATCAAAAGCAGAAGTAGCTGGTGCATTAAAAGTTCCAAAT------GAAGTAAATGGATATTCTAGTTCTTCAGAGAAG ATAGACTTATTGGCCAGTGATCCTCATAATGCTTTAATATTTGCAAGTGAAAGAGTCCAATCCAAACCAGCAGAGAGTAA C---ATCAAAGATAAAATATTTGGGAAAACCTATCACAGGAAGGCAAGCTTTCCTAACTTGAGCCACATAACTGAGGATC TTTTTATAGGAGCTATTGCTACAGAACCCAAGATAATACAA--------------------------------------- ---------------------GAGCATTCCCTCACAAATAAAATAAAGCGTAAAAGGAGAACTACGTCATGCCTTCATCC TGAGGATTTTATCAAGAAAGTAGATTTGACAGTTGTTCAAAAGACGCCTGAAAAGATAAATCAGGGAACTGACCAAATGG AGCAGAAT---------GATCAAGTGATGAATAGTGCTAATAGTGGTCATGAAAATGAAACAAAAGGTGATTAT---GTT CAGAAAGAGGAAAATGCTAACCCAATAGAA------TCATTGGAAAAAGAATCTGCTTTCAGAACTAAAGGTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTAGAATTAAATATCTATAATTCAAAAGCATCTAAGAAGAATAGGCTGAGGAGGA TGTCCTCTACCAGGCATATTCATGCACTTGAACTAGTAGGCAATAGAAATCCAAGCCCACCTAAACATACTGAACTACAA ATTGATAGTTGTTCTAGCACTGAAGAG---ATAGAGAAAATA---AATTCTAACCAAAAACCAATCAGACACAACAGAAT GCTTCAACTCATGAAAGAAAAAGAAAACACAACTGGAGCTAAAAAGAATAACAAGCCAAATGAACAAATAAGTGAAAGAC ATGCCAGTGATGTTTTCCCAGAACTAAAATTAACAAATGTAACCGATTTTCTTCCTAAATGTTCAAATCCTGATAAACTT CAAGAATTTGTTAATTCTAGCCTGCAAGGGGAAGTAGCA---GAGAAC---CTAGAAACAATTCAAGTGTCTGATACTAC CAGGAATCCTGAAGATCTGGTGTTAAGTGAAGGAAAG---AGTTTGCAA---ACTCAAAGGTCTGCAGAGAGTACCAGTA TTTCAGTGGTACCTGATACTGATTATGGCACTCAAGACAGTGTCTCATTACTGGAAGCTGACACCCTGGGG---AAGGCA AAA---ACAGCACTAAATCAACCTATGAGTCAGTATGCAGCAATTAAAAATGCCACTGAACTCTCCCATGGTTGT---GC TAAAGACACTAGAAATGACACTGAGGATTTTAAGGATCCGTTGAGACATGAAGTTACC---CACACTCAGGAGACTAGTG TAGAAATGGAAGAGAGTGAACTTGATACTCAGTATTTACAGAATACATTCAAGATTTCAAAGCGTCAGTCATTTGCTCTG TTTTCGAATCCA---------GAAAATGAATGCGCAACAGTGTGTGCCCACTCCAGGTTCTTAGGCAAACAAAGTCCAAA AGTCATTTTTGAATGTAGGCAAAAAGAAGAAAATCAGGGGAAGAAAGAGTCTAAAATCAAACATGTGCAGGCAGTTCATA CAACTGCAGGCTTTCCTGTAGTTTGTCAGAAAGATAAG---CCAGGTGATTATGCCAAATGTAGCATTCAAGAAGTCTCT AGGCTTTGTCAGTCCTCTCAGTTCAGA---GGCAATGAATCTGAACTCATTACTGCAAATGAACATGAAATTTCACAAAA CCCAGATCAAATGCCATCACTTTCTCACATCAGGTCATCTGTTAAAACTAAATGTAAGGAAAAC---CTGTCAGAGGAAA AGTTTGAGGAACTTACAATATCACTTGAAAGAACAGTGGGAAATGAGAACATCGTTCAAAGTACAGTAAGCACAATTAGC CACAATAACATTAGAGAAAACGCTTTTAAAGAAGCCAGCTCAAGCAGTATTAATGAAGTAGGTTCTAGT----------- ----------------------------------------------------GGTGAAAACATTCAAGCAGAACTAGGTA GAAACAGAGCACCTAAATTAAATGCTATGCTCAGATTAGGTCTTATGCAACCTGAAGTCTATAAGCAAAGTCTT---CCT ATAACTAGTTGTAAACATCCTGAAATAAAAAGGCAAGGAGAAAATGAAGAAGCAATTCAGGCTGTTGATACTGATTTCTC TCCACATCTAATTTCAGATAACCTAGAACTA---CCTATGGGAAATAGTCATGTTTCTCAGATTTGTTCTGAGACGCCTG ATGATTTGTTAGATGATGATGAAATAAAGGAAAATAACAGCTTTGCTGAARATGGCATTAAGGAAAGATCTGCTGTTTTT AGCAAAAGTGTCCAGAAAAGAGAGTTCAGAAGGAGTCCTAGCCCTTTAGGCCAT---ACAAGTTTGGCTCAGGGTCACCA AAGAAGGGCCAGGAAATTAGACTCCTCAGAAGAGGACGTATCTAGTGAG >Anteater TGTGGCACAAATATTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAAAGAATGTAGA AAAGGCTGAATTCTGTGATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAGCAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCACACTACCAGCACAGAGAAAAAAGTAGATGTGGATGCTGATCCCCTGCATCGGAGAAAAGAA CTGAAGAAGTGGAAATCTCCATACTCTGAGAATCCTAGAGGT---ACCCAAGAT---ATTCCTTGGATAACACTGAATAG TAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGACATATTGACTTCTAATGACTCATGCAATGAGGGGTCTG AATTAAATGCAGAAGTAGCTGATGCATCAAAAGTTCCAAAT------GACGTAGATAGATATTCTGGTTCTTCAGAGAAA ATAGACTTAATAGCCAGTGACCCTCATAATGCTTTAATATGTGCAAGTGAAAAAGTCCAGTCCAAACCAACAGAGAGTAA T---ATCAAAGATAAAATATTTGGGAAAACCTATCACAGGAAGGCAAGCCTCCCTAACTTGAGCCGTATAGCTAAAGATC TTTTTATAGGAGCTGTTGCTGCAGAACCTAAGATAACACAA--------------------------------------- ---------------------GAGCTCCCCCTGACAAATGAAATGAAGCTTAAAAGGAGGACTACATCAGGACTTCATCC TGAGGATTTTATCAAGAAAGTAGATTTGACAGTTGTTCAAAAGAAGCCTAAAATGATAAATCAGGGAACTAACCAAATAG AGCAGAAT---------TGTCAACTGATGAATATTGCCAATAGTGGTAATGAAAATGAAACAAAAGGTGATTTT---GTT CAGAAGGAGAAAAGTGCTAACCCAACAGAA------TCATCAGAAAAAGAATCTGCTTTCAGAACTAAAGGTGAACCTAT AAGTAGTAGTATAAGCAATATGAAACTAGAATTAAATACCTGCAATTCAAAAGCATCTAAGAAGAATAGGCTGAGGAGAA TGTCCTCTACCAGGCATATGCATGCACTTGAACTAGTAGCCAATAGAAAGCCAAGCCAGCCTAATCACACTGAACTACAA ATTGATAGTTGTTCTAGCAGTGAAGAA---ATAAAGAAAAAA---AAATCTGACCAAAAGCCAATAAGACACAGCAGAAC AGTTCAATTCATGAAAGATAAAGAAACTGCAATTGGAGCCAAGAAGAGTAACAAGCGAAATGAACAAATAAATAAAAGAC ATGCCAGTGATGCTTTCCCAGAACTAAATTTAACAAACGTAACTGGTTTTCCTACTAAATGTTCAAATTCTGATAAACTT CAAGAATTTGTCAATTCTAGCCTGCAAGGAGAAGCAGCA---GAGAAC---CTAGAAACAATACAAGTGTCTGATACTAC CATGGACCCTGAAGGTCTGGTATTAAGTGAAGGAAAG---AATTTGCAA---ACTGAAAGATCTGTAGAGAGCACCAGTA TTTCATTGGTGCCTGACACTGATTATGGCACTCAAGATAGTATCTCATTACTAGAAGCTGCTACCCTAGGG---AAAGCA AAA---GCAGCACCAAATCAACATGTGAGTCTGTGTGCAGCAGTTGGAAATGCCACTGAACTTGTCCATGGTTGT---TC TAAAGATACTAGAAATGACACTGAAGATTTTAAGGATTCATTGAGACATGAAGTTAAC---CACACACAAGGGACAGTCA TAGAAAAGGAAGAGAGTGAACTTGATACTCAGTATTTNNNNNNNNNNTACAAGATTTCAAAGCGTCAGTCATTTGCTCTG TATTCAAATTCT---------GAAAAGGAATGTGTAACAATCTGTGCCCACTCCAGGTCCGTACGGAAACAAAGTCCAAA AGTAACTTTTGACTATAGACAAAAAGAAGAAAATCAAGGAAAGAAAGAGTCTAAGATCAAACATGTGCAGGCAGTTCATA CAACCGCAGGCTTCTCTGTAGTTTGTCAGAAAGATAAGAAGCCCCATGATTATGCCAAGTGTAGCATTCAGGGAGTCTCT AAGCTTTGTGAGTCATCTCAGTTCAGA---GGCAATGAATCTGAACTCATTACTGCAAACGAACATGGAATTTCCCCAAA TCCAGATCAAATGCCATCACTTTCTCCCAACAGGTCATCTGTTAAAACTAAATATAAGAAAAAC---TTGTCAGAAGAAA GGTTTGAGGAACATACAGTGTCACTTGATAGAGCAGTGGGAAATGAGAGCATCATTCAAAGTACAGTAAGCACAATTAGC CAAAATAACATTAGAGAAAGCACTTTTAAAGAAGCCAGCTCAAGCAGTATTAATGAAGTAGGTTCCAGTATTAATGAAGT GGGTTCCAGTATTAATGAAGTGGGTTCCAGT---------------------GGTGAGAACGTTCAAGCAGAGCTAGGTA GAAACAGA---CCTAAGCTAAATGCTATGCTCAGATTAGGTCTTATGCAACCTGAAGTCTATGAGCAAAATCTT---CCT ATAACTAATTTTAAACTTTCTGAAATTAAAAAACAAGGAGAAAATGAAGAAGTAGTTCAGGCTGTTAATACAGATTTCTC CCCATGTCTAATTTCAGATAACCTAGAACTG---CCTATGGGAAGTAGTCGTGTTTCTCAGATTTGTTCTGAGACACCTG ATGACCTGTTAGATGATGATGAAATAAAGGAAAATAACAGCTTTGCTGAAAGTGGCGTTAAGGAAAGATCTGCTGTTTTT AGCAAAAGTGTCCAGAGAAGAGAATTCAGAAGGAGCCCTAGCCCTTTAGCCCAA---ACAAGTGTGGCTCAGGGTCACCA AAGAGGGGCCAGGAAATTAGCCTCCTCAGAAGNGGACNAGTCTAGNGAG >Sloth TGTGGCACATATACTCATGCCAGCTCATTACAGCGTGAGAACAGCAGTTTATTACTCACTAAAAACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAGCAGCCTGGCTTAGCAAGGAGCCAACAGAACAGATGGGCTGAAAGTAAGGAAA CACGTAATGAT---AGGCAGACTCCCAGCACAGAGAAAAAGGTAGATGTGGATGCTGATCCCCTGTATGGGCGAAAAGAA CTGAATAAGCAGAAACCTCCATGCTCTGAGAGTCCTCAAAAT---ACCCAAGAT---ATTCCTTGGATAACACTGAATAG TAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGACATACTAACTTCTGATGACTCACACAATGGGGGGTCTG AATCAAATGCAGAAGTAGTTGGTGCATTGAAAGTTCCAAAT------GAAGTAGATGGATATTCTGGTTCTTCAGAGAAG ATAGACTTAATAGCCAGTGATCCTCACAATGCTTTAATATTTGCAGGTGAAAGAGTCCAGTCCAAACCAACAGAGACTAA C---ATTGAAGATAAAATATTTGGGAAAACCTATCACAGGAAGGCAAGCCTCCCTAACTTGAGCCACATAGCTGAAAATC TTTTTATAGGAGCCATTGCTACAAAACCTAAGATAACACAA--------------------------------------- ---------------------GAGCACCCCCTGACAAAGAAAATAAAGCATAAAAGTAGGACTACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGTCGATTTGACAGTTGTTCAAAAGATGCCTGAAAAGATAAATCAGGGAACTGACCAAATGG AGCAGAAG------AATAGTCAAGTGATAAATATTGCTAATAGTGGTCATGAGAATGAAACAAAAGATGATTAT---GTT CAGAAAGAGAAAAATGCTAACCCAACAGAA------TCATTGGAAAAAGAATCTGCTTTCAGAACTGAAGGTGAACCCAT AAGCAGCAGTATAAGCAATATGGAACTAGAATTAAATATCTTCAATTCAAAAGTATCTAAGAAGAATAGGCTGAAGAGGA TGTCCTCTACCAGGCATATTCATGCACTTGAACTAGTAGCCAATAGAAATCCAAGCCAACCTAATCATAATGAACTACAA ATTGATAGTTGTTCTAGCAGTGAAGAG---ATAAAGAAAGAA---AATTCTGTCCAAAAGCCAATAAGGCACAGCAGAAT GCTTCAACTCCTGAAAGGTAAAGAAACTCCAACCGTAACCAAGAAGAGTAACAAGCGAAATGAACAAATAAGTAAAAGGC ATTCCAGTGATGCTTTCCCAGAACTAAATTTAACAAATGTAACTGGTTTTCTTACTAAATGTTCAAGTTCTGATAAACTT CAAGAATTTGTCAATTCTAGCCTGCAAGGAGAAGTAGCA---GAGAAC---CTAGAAACAATTCAAGTGTCTGATAGTAC CAGAGACCCCGGAGCTCTGGTGTTAAGTGGAGGAAAG---GGTTTGCAA---ACTGAAAGATCTCTAGAGAGTACCAGTA TTACAATGATACCTGAAACTGATTATGACACTCAAGACAGTATCTCCTTACTGGAAGCTGACACCCTAGGG---AAAGCA AAA---GCAGCACCAAATCAACATGTGAGTCAGTATGCAGCAATTGGAAATGCCACTAAACTTTTCCATGGTTGT---TC TAAAGATACTAGAAGTGACACTGAGAATTTTAAGGATCCATTGAGACATGAAGTTAAC---CACACACAGGAGACATTTG TAGAAATGGAAGAGAGTGAACTTGATACTCAGTATTTACAGAATACATTCAAGATTTCAAAGCGTCAATCATTTGCTCTG TTTTCAAATCCA---------GAAAAGGAATGCGCAACAGTCTCTGCCCACTCCAGGCCCTTAGGAAAACAAAGTCCAAA AGTCACTTTTGACTGTAGACAAAAAGAA---GATCAGGAGAAGAAGGAGTCTAAAATCAAACACGTGCAGGCAGTTCATA CAACTGCAGACTTTCCTGTAGTTTGTCAGAAAGATAAG---CCAGGTGATTATGCTAAATGTAGCATTCAAGGAGTCTCT AAGCTTTGTCAGTTATTTCAGTTCAGA---GGCAATGAATCTGAACCCATTACTGCAGATGAACATGAAATTTCACAAAA TCCAGATCAGATGCCATCACTTTCTCCCATGAAGTCATCTGTTAAAAGTAAATTTAAGGAAAAC---CTGTCAGAGGAAA GATTTGAGGAACATACAGTATCACTTGAAAGAGCAGTGGGAAAGGAGCACATCATTCAAAGGACAGTGAGTCCAATTAGC CAAAATAACATTAGAGAAAGCGCTTTTAAAGAAGCCAGCTCAAGCAGTATCAATGAAGTAGGTTCCAGTGTTAATGAAGT AGGTTCCAGTGTTAATGAAGTAGGTTCCAGT---------------------GGTGAGAACACTCAAGCAGAGCTAGGTA GAAACAGAGGATCTAAATTAAGTGCTATGCTCAGATTAAGTCTTATGCAACCTGAAGTCTATAAGCAAAGTCTT---CCT ATAACTAATTGTAAGCATCCTGAAATTAAAAAGCAAGGAGAAAATGAAGAAGTAGTTCAGGCTGTTAAAACA-------- ----TGTCTAATTTCAGATAACCTAGAACTA---CCTATGGGAAGTAGTCATGCTTCTCAGATTTGTTCTGAGACACCTG ATGATCTGTTAGATGATGGTGAAATAAAGGAAAATAACAGCTTTGCTGAAAGTGGCATTAAGGAAAGATCTGCTGTTTTT ACCAAAAGTGTCCAGAAAAGAGAGTTCAGAAGGAGCCCGAGCCCGTTAGCCCAA---ACAAGGGTCACC---------AA AAGACGGGCCAGGAAATTAGACTCCTCAGAAGAGGATGTGTCTAGTGAG >Dugong TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAATAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTCATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAGCAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCTAGCACAGAGAAAAAGGTAGATATGAATGCTAATCCATTGTATGAGAGAAAAGAA GTGAATAAGCAGAAACCTCCATGCTCCGAGAGTGTTAGAGAT---ACACAGGAT---ATTCCTTGGCTAACACTGAATAG TAGCATTCAGAAAGTTAATGAGTGGTTTTTCAGAAGTGATGGCCTG---------GATGACTTGCATGATAAGGGGTCTG AGTCAAATGCAGAAGTAGCTGGTGCTTTAGAAGTTCCAGAA------GAAGTACATGGATATTCTAGTTCTTCAGAGAAA ATAGACTTAATGGCTAGTGATCCTCATAGTGCTTTAATATGTGAAAGTGAAAGAGTCCTCTTCAAACCAGCAGAAAGTAA C---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAATTCTCCCTCATTTGAGCCATGTAACTGAAGATC TAATTATAGGAGCTGTTGCTACAGAACCTCAGATAGCACAA--------------------------------------- ---------------------GAACGTCCTCTTACAAATAAATTAAAGCGTAAAAGGAGA---ACATCAGGCCTTCATCC TGAGGATTTCATCAAGAAAGTAGATTTGGCAGTTGTTCAAAAGACTCCTGAAAAGATAAATCAAGAAACTGACCAAGTGG AGCAGAAT---------GGTCAAGTGATGAATATTGCTAATGGTGGTCATGGAAATGAAACAAAAGATGATTAT---GTT CAGAAAGAGAAGAATGCTAACCCAACAGAA------TCACTGACAAAGGAATCTGCTTTCAGAACTAAAGCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTAGAATTAAATATGCATAATTCAAAAGCACCGAAGAAGAACAGGCTGAGGAGGA AGTCCTCTACCAGGCATATTCATGCACTTGAACTAGTAGTCAATAGAAATCCAAGTCCACCTACTCATACTGAACTACAA ATTGATAGTTGGTCTAGCAGTGAAGAG---ATAAAGAAA------AGTTCTGAGCAAAAGCCAGTCAGACACAACAGAAA CCTTCAACTCATGAAAAACCAAGAAACCACAACTGGAGCCAAGAAAAGTAACAAGCCAAAGGAACAAATAAGTAAAAGAC ATGCCAGTGACGCTTACCCAGAACTAAATTTAACAAGCACAACTGGCTTAATTACTAACTGTTCAAGTTCTCATAATTAT CAAGAATTT---AATCCTAGCCTTCAGGGAGAAGAAATAGAAGAAAAT---CTGGGAACAATTCAAGTGTCTAATAGAAC CAGAGACCCCGAGGATCTAGTGTTAAATGGAGGAAGA---GGTTTGCAA---ACTGAAATATCTGTTGAGAGTACCAGTA TCTCAGTGATACCTGATACTGACTATGGCAGTCAGAACAGCATCTCATTACTGGAAGCTGACACCCTCAGG---AAGGCA AAA---ACAGCACCAAATCAATGTGCAAGTCAGTGTGCAGCAATTGAAAACCCCAATGAACTTATCCATGGTTGT---CC TAAAGATACTAGAAATGACACAGAGGATTTTAAGGATCTGTTGAGATGTGAAGTTAAC---CACATTCAGGAGACGTGCG TAGAAATGGAAGACAGNGAACTTGATACTCAGTATTTGCAGAGTACATTCAAGGTTTCAAAGCGTCAGTCATTTGCTCTG TTTTCAAATCCA---------GAAAAGGAATGTGCAACAATTTGTGCCCACTCCAAGTCCTTAAGGAAACAAAGTCCAAA AGTCACTCCTGAGTATGGAGAAGAAGAAGAAAATCAAGGGAACAAAGAGTCTAAAATCAAGCATGAGCAGGCAGTTCATA CGACTGCGGGCTATCCTGAGGATTGTCAGAAAGAGAAGAAGCCAAGTGATTATACCAAAAGTAGCATCAAAGGAGTCTCT AGGCTTTGTCAGTCATCTCAGTTCAGA---GGCAGTGAATCCCAACACATTACTGCAGGTGAACATGGAATTTCACAAAA TCCAGATCAAATGCCATTGCTTTCTCCCATCAGGGCATCTGTTAAAAGT------AAGAAAAAC---TTGTCAGAAGAAA GGTTTGAGGAACATACAATATCACTTGAAAGAGCAGTAGGAAATGAGAGCATCGTTCAAAGTACAGTGAGCACAGTTAGC CAAAATGACATTAAGGAAAGTGCTTCTAAAGAAGCCAGCTCAAGCAGTATTAATGAAGTAGGTTCTAGT----------- ----------------------------------------------------GGCGAAAACATTCGAGCAGAGCTAGGTA GGAACAGAGGACCTAAATTAAATGCTGTGCTCAGATTAGGTCTTATGCAACCTGAAGTCTATAAACAAAGTCTT---CCT GTAAGTAACTGTAAACGTCCTGAAATAAAAAGGCAAGGAGAAAATGAAGGAGTAGTTCAGGATGTTAATATGGATTTCTC TCCATGTCTAATTTCAGATAACCTAGAACAA---CCTATGGGAAGTAGTCGTGCTTCTCAGATTTGTTCTGAGACTCCTG ATGACCTGTTAGATGATGATGAAATAAAGGAAAATATCAGCTTTGCTGAAAGTGGCATTAAGGAAAGATCTGCTGTTTTT AGTAAA---GACCAGAGAAGAGAGTTCAGAAGGAACCCAAGCCCTTTATCCCAT---TCAGGTTTGGCTCAGGGTCACCT AAGAGGGGCCAGGGAATTAGAGTCCTCAGACGAGAACATATCTAGTGAG >Manatee TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAATAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTCATAAAAGCAAACAGCCTGGCTTAACAAGGAGCCAGCAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCTAGCACAGAGAAAAAGGTAGATATGAATGCTAATCCATTGTATGAGAGAAAAGAA GTGAATAAGCAGAAACCTCCATGCTCCGAGAGTGTTAGAGAT---ACACAAGAT---ATTCCTTGGCTGACACTGAATAG TAGCATTCAGAAAGTTAATGAGTGGTTTTTCAGAAGTGATGGCCTG---------GATGACTTGCATGATAAGGGGTCTG AATCAAATGCAGAAGTAGCTGGTGCATTAGAAGTTCCAGAA------GAAGTACATGGATATTCTAGTTCTTCAGAGAAA ATAGACTTAATGGCCAGTGATCCTCATAGTGCTTTAATATGTGAAAGTGAAAGAGTCCTCTCCAAACCAGCAGAAAGTAA C---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAATTCTCCCTCATTTGAGCCATGTAACTGAAGATC TAATTATAGGAGCTGTTGCTACAGAACCTCAGATAGCACAA--------------------------------------- ---------------------GAACGTCCCCTTACAAATAAATTAAAGCGTAAAAGGAGA---ACATCAGGCCTTCATCC TGAGGATTTCATCAAGAAAGTAGATTTGGCAGTTGTTCAAAAGACTCCTGAAAAGATAAATCAGGAAACTGACCAAGTGG AGCAGAAT---------GGTCAAGTGATGAATATTGCTAATGGTGGTCATGAAAATGAAACAAAAGATGATTAT---GTT CAGAAGGAGAAGAATGCTAACCCAACAGAA------TCACTGACAAAGGAATCTGCTTTCAGAACTAAAGCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTAGAATTAAATATGCATAATTCAAAAGCACTGAAGAAGAATCGGCTGAGGAGGA AGTCCTCTACCAGGCATATTCATGCACTTGAACTAGTAGTCAATAGAAATCCAAGTCCACCTACTCATACTGAACTACAA ATTGATAGTTGGTCTAGCAGTGACGAG---ATAAAGAAA------AGTTCTGAGCAAAAGCCAGTCAGACACAACAGAAA CCTTCAACTCATGAAAAACCAAGAAACCACAACTGGAGCCAAGAAAAGTAACAAGCCAAAGGAACAAATAAGTAAAAGAC ATGCCAGTGACACTTACCCAGAACTAAATTTAACAAGCACAACTGGCTTAATTACTAACTGTTCAAGTTCTCATAATTAT CAAAAATTTGTTAATCCTAGCCTTCAGGGAGAAGAAATAGAAGAAAAT---CTGGGAGCAACTCAAGTGTCTAATAGAAC CAGAGACCCCGAGGATCTAGTGTTAAATGGAGGAAGA---GGTTTGCAA---ACTGAAATATCTGTTGAGAGTACCAGTA TCTCAGTGATACCTGATACTGATTATGGCAGTCAGAACAGCATCTCATTACTGGAAGCTGACACCCTCAGG---AAGGCA AAA---ACAGCACCAAATCACTGTGCAAGTCAGTGTGCAGCAATTGAAAACCCCAATGAACTTATCCATGGTTGT---CC TAAAGATACTAGAAATGACACAGAGGATTTTAAGGATCTGTTGAGATGTGAAGTTAAC---CACGTTCAGGAGACATGCA TAGAAATGGAAGACAGTGAACTTGATACTCAGTATTTGCAGAGTACATTCAAGGTTTCAAAGCGTCAGTCATTTGCTCTG TTTTCAAATCCA---------GAAAAGGAATGTGCAACAATTTGTGCCCACTCCAAGTCCTTAAGGAAACAAAGTCCAAA AGTCACTCCTGAGTATGGAGAAAAAGAAGAAAATCAAGGGAACAAAGAGTCTAAAATCAAGCATGAGCAGGCAGTTCATA CAACTGCTGGCTATCCTGAGGATTGTCAGAAAGAGAAGAAGCCAAGTGATTATACCAAATGTAGCACTAAAGGAGTCTCT AGGCTTTGTCAGTCATCTCAGTTCAGA---GGCAGTGAATCCGAACACATT---ACAGGTGAACATGGAATTTCACAAAA TCCAGATCAAATGCCATTGCTTTCTCCCATCAGGGCATCTGTTAAAAGT------AAGAAAAAC---TTGTCAGAAGAAA GGTTTGAGGAACATACAATATCACTTGAAAGAGCAGTAGGAAATGAGAGCATCGTTCAAAGTACAGTGAGCACAGTTAGC CAAAATAACATTAAGGAAAGTGCTTCTAAAGAAGCCAGCTCAAGCAGTATTAATGAAGTAGGTTCCAGTGTTAATGAAGT AGGTTCTAGT------------------------------------------GGCGAAAACATTGAAGCAGAGCTAGGTA GGAACAGAGGACCTAAATTAAATGCTGTGCTCAGATTAGGTCTTATGCAACCTGAAGTGTATAAACAAAGTCTT---CCT GTAAGTAACTGTAAACATCCTGAAATAAAAAGGCAAGGAGAAAATGAAGGAGTCGTTGAGGATGTTAATATGGATTTCTC TCCATGTCTAATTTCAGATAACCTAGAACAA---CCTATGGGAAGTAGTCGTGCTTCTCAGATTTGTTCTGAGACTCCTG ATGACCTGTTAGATGATGATGAAATAAAGGAAAATATCAGCTTTGCTGAAAGTGGCATTAAGGAAAGATCTGCTGTTTTT AGTAAA---GACCAGAGAAGAGAGTTCAGAAGGAACCCAAGCCCTTTATCCCGT---TCAGGTTTGGCTCAGGGTCACCT AAGAGGGGCCAGGGAATTAGAGTCCTCAGAAGAGAACATATCTAGTGAG >AfricanEl TGTGGCACAAATACTCATGCCAGCTCATTACAGCATAAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAACAAAAGCAAACAGCCTGGCTTAGCAAGAAGCCAACAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCTAGCACAGAGAAAAAGGTAGATGTGAATGCTGATCCCTTGTATGAGAGAAAAGAA GTGAATAAGCAGAAACCTCCACGCTCTGAGAATCTTAGAGAC---ACCCAAGAT---ATTCCTTGGATAACACTGAATAG TAGCATTCAGAAAGTTAATGAGTGGTTTTTCAGAAGTGACGGCCTG---------GATGTCTTAAATGATGAGGGGCCTG AATCCAGTGCAGAAGTAGCTGGTGCATTAGAAGTTCCAAAT------GAAGTACAT------TCTAATTCTTCAGAGAAA ATAGACCTAATGGCCAGTGATCTGCATGGTGCTTTAATATGTGAAAGTGAAAGAGTCCCCTCCAAACCAGCAGAAAGTAA C---ATCGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAGGTATGTCTCATTTGAGCCACATAACTGAAGATC TGATTATGGGAGCTATTGCTTCAGAACCTCAGATAGCACGA--------------------------------------- ---------------------GAACATCCTTTTACAAATAAATTAAAGCGTAAAAGGAGA---ACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGTAGATTTGGCAGTTGTTCAAAAGATCCCTGAAAAGATAAATCAGGAAACTGACCATGTGG AGCAGAAC---------GGTCAAGTGATGAATATTGCTAATGGTGGTCGTGAGAATGAAACAAAAGGTGATTAT---GTT CAGAAAGAGAAGAATGCTATCCCAACAGAA------TCATTGGCAAAAGAATCTGCTTTCAGAACTAAAGCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAACTAGAATTAAATATGCATAATTCAAAAGCACCAAAGAAGAATAGGCTGAGGAGGA AGTCGTCAACCAGACATATTCATGCACTTGAACTAGTAGTCAATAGAAATCCAAGTCCACCTACTCATACTGAACTACAA ATTGACAGTTGGTCTAGCAGTGAAGAG---ACAAAGAAAAAA---AGTTCTGAGCAAAAGCCAATCAGACACAACAGAAA CCTTCAACTCATGAAAAATCAAGAAACCGCAACTGGAGCCAAGAAGAGTAACAAGCCAAAGGAACAAATAAGTAAAAGAC ATGGCGCTGACTCTTACCCAGAACTACATTTAACAACCACAGCTGGCTTTATTACTAAGTGTTCAAGTTCTGATAATCTT CAAGAATTTGTCAATCCTAGCCTTCAAGGAGAGAAAACAGAAGAAAAC---CTGGAAACAATTCAAGTGTCTAATATTAC CAAAGAGCCCAAGGATCTAGTGTTAAATGGAGGAAGA---GATTTGCAA---ACCAAAAAATCTATTGAGAGTACCAATA TCTCAGTGATACCTGATACTGTTTATGGCACTCAGGACAGCGTCTCATTGCTGGGAGCTGACACCCCAGGG---AAGGCA AAA---ACAGCACCAAATCGATGTGCAAGTCAGTGTACAGCAATTGAAAACCCAAGTGAACTTACCAACAGTTGT---CC TAAAGATACTAGAAATGACACAGAGGGTTTTAAGGATCTATTGAGATGTGAAGCTAGC---CACATTCAGGAGACATGCA TAGAAATAGAAGAGAGTGAACTTGATACTCAGTATTTGCAGAGTACATTCAAGGTTTCAAAGCGTCAGTCATTTGCTCTG TTTTCAAATCCA---------GAAAAGAAATGTGCAACAATTTGTGCCCACTCCAAGTCCTTAAGGAAGCAAAGCCCAAA AGTCACTCTTGTGTGTGGAGAAAAAGAAGAAAATCAAGGGAACAGAGAGCCTAAAATCAAGCATGAGCAGGCAGTTCATA TGCCTACAGGCTATCCTGAGGCTTGTCAGAAAGAGAAG---CCAAGTGACTATACCAAATATAGCATTAAAGGAGTCTCT GGGCTTTGTCAGTCATCTCAGTTCAGA---GGCAGTGAATCTGAACTCATTACTGCAGATGGACATGGAATCTCACAAAA CCCAGATCAAATACCATCACTTTCTCCCACCAGGTCATCTGTTAAAACTAAATGTAAGACAAAC---CTGTTGGAAGAAA GGTTTGAGGAACATACAATATCACTTGAAAGAGCAATGAGAAATGAGAACGTCATTCAAAGTACAGTGAGCACAGTTAGC CAAAATAACATTAGGGAAAGTGCTTCTAAAGAAGCCAGCTCAAGCAGTATTAATGAAGTATGTTCCAGTATTAATGAAGT AGGTTCTAGT------------------------------------------GGTGAAAACATTCAAGCAGAAATAAGTA GGAAGAGAGGACCTAAATTAAATGCTGTGCTCAGATTAGGTCTTATGCAACCTGAAGTTTATAAACAAAGTCTT---CCT ATAAGTGACTGTAAACATCCTGGAATAAAAACGCAAGGAGAAAATGAAGGAGTAGTTCAGGCTGTTAATACAGATTTCTC CCCATGTCTAATTTCAGATAACCTAGAACAA---CCTGTGGGAACTAGTCGTGCTTCTCAGGTTTGTTCTGAGACTCCCG ACGACCTGTTAGATGATGATGAAATAAAGGAAAATATCAGCTTTGCTGAAAACGGCATTAAGGAAAGATCT---GTTTTT ATTAAAGATGACCAGAGAAGAGAGTTCAGAAGGAACCCAAGCCCTTTATCCCAT---TCAGGTTTGGCTCAGGGTTGCCT AAGAGGGGCCAGGGAATTGGAGCCCTCACAAGAGAACATATCTAG---- >AsianElep TGTGGCACAAATACTCATGCCAGCTCATTACAGCATAAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAACAAAAGCAAACAGCCTGGCTTAGCAAGAAGCCAACAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCTAGCACAGAGAAAAAGGTAGATGTGAATGCTAATCCCTTGTATGAGAGAAAAGAA GTGAATAAGCAGAAACCTCCACGCTCTGAGAATCTTAGAGAC---ACCCAAGAT---ATTCCTTGGATAACACTGAATAG TAGCATTCAGAAAGTTAATGAGTGGTTTTTCAGAAGTGACGGCCTG---------GATGTCTTAAATGATGAGGGGCCTG AATCCAGTGCAGAAGTAGCTGGTGCATTAGAAGTTCCAAAT------GAAGTACAT------TCTAATTCTTCAGAGAAA ATAGACCTAATGGCCAGTGATCTGCGTGGTGCTTTAATATGTGAAAGTGAAAGAGTCCCCTCCAAACCAGCAGAAAGTAA C---ATCGAAGATAAAATATTTGGGAAAACCTATCGGAGGAAGGCAGGTATCTCTCATTTGAGCCACATAACTGAAGATC TGATTATGGGAGCTATTGCTTCAGAACCTCAGATAGCACGA--------------------------------------- ---------------------GAACATCCTTTTACAAATAAATTAAAGCGTAAAAGGAGA---ACATCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGTAGATTTGGCAGTTGTTCAAAAGATCCCTGAAAAGATAAATCAGGAAACTGACCATGTGG AGCAGAAC---------GGTCAAGTGATGAATATTGCTAATGGTGGTCGTGAGAATGAAACAAAAGGTGATTAT---GTT CAGAAAGAGAAGAATGCTATCCCAACAGAA------TCATTGGCAAAAGAATCTGCTTTCAGAACTAAAGCTGAACCTAT AAGCAGCAGTATAAGCAATATGGAGGTAGAATTAAATATGCATAATTCAAAAGCCCCAAAGAAGAATAGGCTGAGGAGGA AGTCGTCAACCAGGCATATTCATGCACTTGAACTAGTAGTCAATAGAAATCTAAGTCCACCTACTCATACTGAACTACAA ATTGACAGTTGGTCTAGCAGTGAAGAG---ACAAAGAAAAAA---AGTTCTGAGCAAAAGCCAATCAGACACAACAGAAA CCTTCAACTCATGAAAAATCAAGAAACCGCAACTGGAGCCAAGAAGAGTAACAAGCCAAAGGAACAAATAAGTAAAAGAC ATGGCGCTGACTCTTACCCAGAACTACATTTAACAACCACAGCTGGCTTTATTACTAAGTGTTCAAGTTCTGATAATCTT CAAGAATTTGTCAATCCTAGCCTTCAAGGAGAGAAAACAGAAGAAAAC---CTGGAAACAATTCAAGTGTCTAATATTAC CAAAGAGCCCAAGGATCTAGTGTTAAATGGAGGAAGA---GATTTGCAA---ACCAAAAAATCTATTGAGAGTACCAATA TCTCAGTGATACCTGATACTGTTTATGGCACTCAGGACAGCGTCTCATTGCTGGGAGCTGACACCCCAGGG---AAGGCA AAA---ACAGCACCAAATCAATGTGCAAGTCAGTGTACAGCAATTGAAAACCCAAGTGAACTTACCAACAGTTGT---CC TAAAGATACTAGAAATGACACAGAGGGTTTTAAGGATCTATTGAGATGTGAAGCTAGC---CACATTCAGGAGACATGCA TAGAAATAGAAGAGAGTGAACTTGATACTCAGTATTTACAGAGTACATTCAAGGTTTCAAAGCGTCAGTCATTTGCTCTG TTTTCAAATCCA---------GAAAAGAAATGTGCAACAATTTGTGCCCACTCCAAGTCCTTAAGGAAGCAAAGCCCAAA AGTCACTCTTGTGTGTGGAGAAAAAGAAGAAAATCAAGGGAACAGAGAGCCTAAAATCAAGCATGAGCAGGCAGTTCATA TGCCTGCAGGCTATCCTGAGGCTTGTCAGAAAGAGAAG---CCAAGTGACTATACCAAATATAGCATTAAAGGAGTCTCT GGGCTTTGTCAGTCATCTCAGTTCAGA---GGCAGTGAATCTGAACTCATTACTGCAGATGGACATGGAATCTCACAAAA CCCAGATCAAATACCATCACTTTCTCCCACCAGGTCATCTGTTAAAACTAAATGTAAGACAAAC---CTGTTGGAAGAAA GGTTTGAGGAACATACAATATCACTTGAAAGAGCAATGAGAAATGAGAACGTCATTCAAAGTACAGTGAGCACAGTTAGC CAAAATAACATTAGGGAAAGTGCTTCTAAAGAAGCCAGCTCAAGCAGTATTAATGAAGTATGTTCCAGTATTAATGAAGT AGGTTCTAGT------------------------------------------GGTGAAAACATTCAAGCAGAAATAAGTA GGAAGAGAGGACCTAAATTAAATGCTGTGCTCAGATTAGGTCTTATGCAACCTGAAGTTTATAAACAAAGTCTT---CCT ATAAGTGACTGTAAACATCCTGGAATAAAAACGCAAGGAGAAAATGAAGGAGTAGTTCAGGCTGTTAATACAGATTTCTC CCCATGTCTAATTTCAGATAACCTAGAACAA---CCTGTGGGAACTAGTCGTGCTTCTCAGGTTTGTTCTGAGACTCCCG ACGACCTGTTAGATGATGATGAAATAAAGGAAAATATCAGCTTTGCTGAAAACAGCATTAAGGAAAGATCT---GTTTTT ATTAAAGATGACCAGAGAAGAGAGTTCAGAAGGAACCCAAGCCCTTTATCCCAT---TCAGGTTTGGCTCAGGGTTGCCT AAGAGGGGCCAGGGAATTGGAGCCCTCACAAGAGAACA----------- >RockHyrax TGTGGCACAGATACTTGTGCCAGCTCGTTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGGATGTAGA AAAGGCTGAATTCTGTAGTAAGAGCAAACAGCCTGGCTTAGCAAGGAGCCAACAGAGCAGATGGGCTGAGAGTACGGAAA CATGTAATGGT---AGGCAGATTCTTAGAACAGAGAAAAAGGTAGAAACGAATGCTGATCCTTTGTATGGGAAAAAAGAA GGGAATAAGCAGAAACCTCCATGCTCTGAGAGTCGCACAGAT---ACGCAAGAT---ATTCCTTGGGTAACACTGAATAA CAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGACAACCTA---------AGTGATTCACCTAGTGAGGGGTCTG AATTAAATGGAAAAGTGGCTGGTCCAGTAAAACTTCCAGGT------GAAGTACATAGATATTCTAGTTTTCCAGAGAAC ATAGATTTAATGGCCAGTGGTCCTCCTGGT------------------GAAAGAATCCCCTGCAAACCACCAAAAAGTAA C---ATCAAAGATAAAATATTTGGGAAAACCTATCAGAGGAAGGGAAGTCTCCCTCACCTGAGCCACATAACCGAAGATC TAGTTAAAGGCGCCATTGCTACACAACCACAGATAGCACGA--------------------------------------- ---------------------GAACATCCTCTTACAAATAAGTTACAGCATAAAAGGAGA---ACATCAGGCCTTCATCC TGAGGATTTTATCAAAAAAGCAGATTTGACAGTTGTTCAGAAGGCATCTGAGAAGATAAATCAGGAAACTGACAAAGTGG AGCAGAGT---------GGTCAAGTGATAAATATTGGTAATGGTGGTCATGAGAATGAAACAAAAGATGATTAT---GTT CTGAAAGAGAAGAATGGTAACCCAGCAGAA------TCACTGAAAAAAGAATCTGTGTTCAAAACTAAAGCTGAACCTAT AAGCAACAGTATAAGCAATATGGAACTAGAATTAAATACACATAATTCAAAATCACTGAAGAAGAACAGGCTGAGGAAGA AGTCCTCCTCCAGACATGTTCATGCCCTTGAACTGGTAGTCAATAGAAATCCAAGTTCACCACCTCATACTGGGCTACAA ATTGATAGCTGGTCTGGCAGTGAAGAA---ATGAAGAAAACA---AGTTCTGAGCAAAAGCCAGTCAGACACAACATAAA CCTCCAACTCATGAAAAACCAAGAAACCACAACTGGAGCCAAGAAGAGTAACAAGCCAAAGGAACAAATAAATAAAAGAC ACACTAGTAATCCTTACCCAGAACTAAATTTAACAAGCACAGCTGGCTTTATTACTGTATGTTCAAGTTCTGATAATCTT CAAGAACCTGTCAACCCCAGCCTTCAAGGAGAGGAAATAGAAGAAAAC---TTGGCAACAGTCCAAATGTCTAATACTGC CAAAGAACCTGAGGATCTAGAGTTAAATGGAGGGAGA---GTTTTGCAA---ACCAAAAGATCTGTTGAAAGTACTAGTA CCTCAGTGATACCTGATGCTGACTGTGGTGCTCAGGACAGCATCTCGTTACTGGAAGCTGACACTCTAGGG---AAGGCA AAA---ACAGCACCAAATCAAGGGGCAGGTCAATGTTCGGCAATCGAAAACCCCAACGAACTTATTCATGGTAGT---CC TAAAGACACTAGAAATGATATAGAGGGTTTTAAGGATCCACTGAGATGCAAAGTTAAC---CCTATTCAGGAGATATGTG TAGAAATGGATGAAAATGAACTTGATACTCAGTATATACAGAGTACATTCAAGGTTTCAAAGCGTCATTCTTTTGCTCTG TTTTCAAATCCG---------GAAAAGGAGTGTGCGACAAGTTATACCCACTCCAAGTCGTTAAGGAAAGAAAATCCCAA AGTCACTCTTCAGCGTGGAGAAGAAGAAGAAAATCAAGGGAACAAAGAATCTAAAATCAAGCAT---------GTTCATA CAACTGCAAGCTGTCCTGAGGTTTGTCAGGAAGACACAAAGCCTAGTGATCGTACTAACTGTAGTGTTAAAGGACTCCCT AGGCTTTGTCACTCATCTCAATTCAAA---GGTAGTGAGTCTGAACTCATTACTGAAGGTGAACATGGAATTGCACAAAA CCCGGATCAGATGCCATCATCTTCTCCCATCAGATCATCTGTTAACTCTAAGTGTAACAAAAAC---CTGTCAGAAGAGC GATTTAAGGAACATAAAATATTACTTGAAAGAACAACAGGAAATGAAACCATTGTCCAAAGTACAGTGAGCACAGGTAGC CAAGATAACATTAGGGGAAGTGCTTCGAAAGAAACCAGCTCAAGCAGTATTAATGAAGTAGGTTCTAGT----------- ----------------------------------------------------AGCGAAAACATTCAAGCAGAAATAAGTA GGAACAGAGAACCTAGATTAAATGCTGTGCTCAGGTTAGGTGTTATGCAACCTGAAGTGTATAAACAAAGTCTT---TCT ATAAGTAACTGTAAACAGCCAGAAATAAAAAAGCGAGGAGAAAATGAAGGAGTAGTTCAGGCTGTTAGTACAGATTTCTC TGCATGTCCCATTTCAGAAAACCTAGAACAA---CCTGTGAGAAGTAGTCACACTTCTCAGGTTTGTTCTCAGACTCCTG ATAACCTGTTAGATGATGATGAAATAAAGGGAAAGACTGACTTTGCTGGAAGTAGCATTAAGGACAGACCT---GTCTTT AGTAAAGATGACCAGGGAAGAGAGTTCAGAAGGAACCCAAGCCCTTTATCCCAT---TCAGGTTTGGCTCAGGGCCACCT GATAGGGGCCAGGGAATTAGAGGCCTCACAAGAGAACACATCTAGCGG- >TreeHyrax ------NCAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGGATGTAGA AAAGGCTGAATTCTGTAGTAAGAGCAAACAGCCTGGCTTAGCAAGGAGCCAACAGAGCAGATGGGCTGAGAGTACGGAAA CATGTAATGAT---AGGCAGATTCTTAGAACAGAGAAAAAGGTAGATACAAATGCTGATCCTTTGTATGGTAAAAAAGAA GGGAATAAGCAGAAACCTCCATGCTCTGAGAGTCGCACAGAT---ACGCAAGAT---ATTCCTTGGGTAACACTGAATAA CAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGACAACCTA---------AGTGATTCACCTAGTGAGGGGTCTG AATTAAATGGAAAAGTGGCTGGTCCAGTAAAGCTTCCAGGT------GAAGTACATAGATATTCTAGTTTTCCAGAGAAC ATAGATTTAATGGCCAGTGGTCCTCCTGGTGATTTAATATGTGAAAGTGAAAGAATCCCCTGCAAACCACCAAAAAGTAA C---ATCAAAGATAAAATATTTGGGAAAACCTATCAGAGGAAGGGAAGTCTCCCTCACCTGAGCCACATAACTGAAGATC TAGTTAAAGGCGCCATTACTACACAACCACAGATAGCACGA--------------------------------------- ---------------------GAACATCCTCTTACAAATAAGTTACAGCATAAAAGGAGA---ACATCAGGCCTTCATCC TGAGGATTTTATCAAAAAAGCAGATTTGACAGTTGTTCAGAAGGCATCTGAGAAGATAAATCAGGAAACTGACAAAGTGG AGCAGAGT---------GGTCAAGTGATAAATATTGCTAATGGTGGTCATGAGAAGGAAACAAAAGATGATTAT---GTT CTGAAAGAGAAGAATGGTAACCCAGCAGAA------TCACTGAAAAAAGAATCTGTGTTCAAAACTAAAGCTGAACCTAT AAGCAACAGTATAAGCAATATGGAACTAGAATTAAATACACATAATTCAAAATCACTGAAGAAGAACAGACTGAGGAAGA AGTCCTCCTCCAGACATGTTCATGCCCTTGAACTGGTAGTCAATAGAAATCCAAGTTCACCACCTCATACTGGGCTACAA ATTGATAGTTGGTCTGGCAGTGAAGAA---ATGAAGAAAACA---AGTTCTGAGCAAAAGCCAGTCAGACACAACATAAA CCTCCAACTCATGAAAAACCAAGAAACCACAACTGGAGCCAAGAAGAGTAACAAGCCAAAGGAACAAATAAATAAAAGAC ACACTAGTAATCCTTACCCAGAACTAAATTTAACAAGCACAGCTGGCTTTATTACTGCGTGTTCAAGTTCTGATAATCTT CAAGAACCTGTCAACCCCAGCCTTCAAGGAGAGGAAATAGAAAAAAAC---TTGGCAACAGTCCAAATGTCTAATACTGC CAAAGAACCTGAGGATCTAGAGTTAAATGGAGGGGGA---GTTTTGCAA---ACCAAAAGATCTGTTGAAAGTACCAGTA CCTCAGTGATACCTGATGCTGACTGTGGTGCTCAGGACAGTATCTCGTTACTGGAAGCTGACACTCTAGGG---AAGGCA AAA---ACAGCACCAAATCAAGGGGCAGGTCAATGTTCAGCAATCGAAAACCCCAACGAACTTATTCATGGTAGT---CC TAAAGACACTAGAAATGATATAGAGGGTTTTAAGGATCCACTGAGATGCGAAGTTAAC---CCTATTCAGGAGATATGTG TAGAAATGGATGAAAATGAACTTGATACTCAGTATATACAGAGTACATTCAAGGTTTCAAAGCGTCATTCTTTTGCTCTG TTTTCAAATCCA---------GAAAAGGAGTGTGTGAAAAGTTATACCCACTCCAAGTCGTTAAGGAAAGAAAATCCCAA AGTCACTCTTCAGCGTGGAGAAGAAGAAGAAAATCAAGGGAACAAAGAATCTAAAATCAAGCAT---------GTTCATA CAACTGCAAGCTGTCCTAAGGTTTGTCAGGAAGACGCAAAGCCTAGTGATCGTACCAACTGTAGTGTTAAAGGACTCCCT AGGCTTTGTCACTCATCTCAATTCAAA---GGTAGTGAGTCTGAACTCATTACTGAAGGTGAACATGGAATTGCACAAAA CCCAGATCAGATGCCATCATCTTCTCCCATCAGATCATCTGTTAACTCTAAGTGTAACAAAAAC---CTGTCAGAAGAGC GATTTAAGGAACATAAAATATTATTTGAAAGAACAACAGGAAATGAAACCATTGTCCAAAGTACAGTGAGCACAGGTAGC CAAGATAACATTAGGGGAAGTGCTTCGAAAGAAACCAGCTCAAGCAGTATTAATGAAGTAGGTTCTAGT----------- ----------------------------------------------------AGCGAAAACATTCAAGCAGAAATAAGTA GGAACAGAGAACCTAGATTAAATGCTGTGCTCAGGTTAGGTGTTATGCAACCTGAAGTGTATAAGCAAAGTCTT---TCT ATAAGTAACTGTAAACAGCCAGAAATAAAAAAGCAAGGAGAAAATGAAGGAGTAGTTCAGGCTGTTAGTACGGATTTCTC TGCATGTCCCATTTCAGAAAACCTAGAACAA---CCTGTGAGAAGTAGTCACACTTCTCAGGTTTGTTCTCAGACTCCTG ATAACCTGTTAGATGATGATGAAATAAAGGGAAAGACTGACTTTGCTGGAAGTAGCATTAAGGACAGACCT---GTCTTT AGTAAAGATGACCAGGGAAGAGAGTTCAGAAGGAACCCAAGCCCTTTGTCCCAT---TCAGGTTTGGCTCAGGGCCACCT GATAGGGGCCAGGGAATTAGAGNCCTCACAAGAGAACACATCTAGCAA- >Aardvark TGTGGCACAAATACTCATGCCAGCTCGTTACAGCATGAGAACAGCAGTTTATCACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGTGAGGAGCCAACAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCTTAGCACAGGGGAAAAGGTAGATATGAAGGCTGATCCCTTGTATGGGAGAAAAGAA GTGAATAAGCAGAAACCTCCATGCTCTGAGAATCCTAGAGAT---ACTGAAGAT---ATTCCTTGGATAACACTGAATAG TAGCATTCAGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGGCCTG---------GATGGCTCACATGATGAAGGGTCTG AATCAAATGCAGAAATAGGTGGTGCATTAGAAGTTTCAAAT------GAAGTACATAGTTACTCTGGTTCTTCAGAGAAA ATAGACTTAATGGCCAGTGAACCTCATGTTGCTTTAATATGTGAAAGTGAAAGAGTCCTCTCCAAACCAGCAGAAAGTAA C---ATCGAAGATAAGATATTTGGGAAAACCTATCGGAGGAAGTCGAGTCTCCCTAACATAAGCCATATAACTGAAGATC TAATTTTAGGAGCTATTGCTACAGAACCTCAGGTTGCACGA--------------------------------------- ---------------------GAATGTCCTCTTGGAAATAAATTAAAGCGTAAAAGGAGA---ACATCAGGCCTTCATCC TGAGGATTTTATTAAGAAAGTAGATTTGGCAGTT---CAAAAGACTCCTGAAAAGATAAATCAGGAAAATGACCAAATGG AACAAAAT---------GGTCAGGAGGAGAATATTGCTGATGGCTGTCATGAGAATGCAACAAAAGGTGAATAC---ATG CAGAAAAAGAAGAGTGCAAATCCAACAGAA------TCATTGGCAACAGAATCTGTTTTCAGAACTAAAGCTGAACCTAT AAGCAGCAGTATAAGCAATTTGGAACTAGAATTAAATACACACAATTCAAAGGCATCCAAGAAGAATAAGCTGAGGAGGA AATCCTCTACCAGGCATATTCATGCACTTGAACTAGTAGTCAATAGGAATCCAAGTCCCCCTAGTCATACTGAGTTACAG ATTGATAGCTGGCCTAGCAGTGAAGAG---TTAAAGAAAAAA---AGTTCTGAGCACAAGCCAATCAGACAGAATACAAA CCTGCAACTCATGAAAGATCAAGAGGCCACAACTGGGGCCAAGAAGAGTAACAAGCCAAATGAACAAATAAGTACAGGAC ACGCCTCTGACATTTTCCCAAAATTGAATTTAACAAACATAACTGGTTTTATTACTAATTGTTCAAGTTCTGATAATCTT CAAGAATTTGTCAATCCTAGCCTTCAAGAAGAGGAAATAAAAGAGAAC---CTGGGAACAATTCAAGTGTCTGATAGTAC CAGAGATCCTACGGATGAGGTGTTAAAC---AGAAGA---GGTTTGCAA---ACTGAAAGATCTGTGGAGAATACCAGTA TTTCAGTGAAACCTGATACTGATTATAGCACTCAGGACAGCATCTTATTACTGAAAGCTAACTCCCTAAGG---AAGGCA AAA---ACAGCACCA------------AGTCAGTGTGCAGCAATTGAAAATCCTAACAAACTTAGCCATGGTTTT---CC TAAAGATACCAGAAATGACATAGAGGGTTTTAAGGATCTATTTAGAGGTGAAGATAAC---CACGTTCAGGAGACATACA TAGAAATGGAAGAGAGTGAACTTGATACTCAGTATTTACAGAATACATTCAAGGTTTCAAAGCGTCAGTCATTTGCTCTG TTTTCAAATCCA---------GAAAAGGAATTTGCAACAGTCCATGCCCACTCCAGGTCCTTGAGGAAACAAAGTCCAAA CATCACTCTTGAGTGTGGAGAAAAAGAAGAAAATCAGGGGAACGAGGAATCTAAAATCAAGTGCGTACAGCTAGTTCTTT CAACTACAGGCTATGCTGGAGCTTGTCAGAAAGAGAAG---CCAAGTGATTATGCCAAATGTAGCATTAAAGGAGTCTCT AGACTTTGTCAGTCATCTCAATTCAGA---GGCAATGAATCTGAAATCATTACTGCAAATGAACATGGAGTCTCACAAAA CCTGGATCAGACACCATCACTTTCTCCCACTAGGTCATCTGTTAAAGCTAAATGTAAGACAAAT---CTGTCCAAAGAAA GATTTGAGCAACAGAAAATATCACATGAAAGAGTAATGGGAAATGAGAGCACCATTCAGAGTACAGTGGGCACAGTTAGC CAAAGTAACATTAGGGAAAGTGCTTTTAAAGAAGCTAGCTCAAGCAGTATTAATGAGGTAGGTTCCAGTGTTAATGAAAT AGGTTCTAGT------------------------------------------GGTGAAAACATTCAAGCAGAACTAGGTA AGAACAGAGGACCTAAATTGAATGCTGTGCTCAAATTATGTCTTATGCAACCTGAAGAGTATAAACAAAGTCCT---CCT ATAAGTAATTGTAAACATCCTTCAATAAAAACCCAAGGACAAAATGAAGGAGTAGTTCAGGCTGTTAATACAGGTTTTTC TTCATGTCTGATTTCAGATAACCTAGGACAA---CCTATGGGAAGCAGTCATGCTTCTCAGATTTGTTCTGAGACACCTG ATGACCTGTTAGATGATGACAAAATAAAGGAAAATACCAGCTTTGCTGTAAGTGGCATTAAGGAAAGATCTGCTGTTTTT AGTAAAGATGACCAGGAAAGAGAGTTCAGAAGGAGCCTGAGCCGTTTCTCCCAT---TCAAGTTTGGCTCAGGTTCACGT AAGAGGTGCCAGGGAATTAGAGTCCTCAGAAGAGAACATATCTAGTGAG >GoldenMol TGTGGCACAAATACTCATGCCAGCTCATTACAGCATGAGAACAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTGTAATAAAAACAAACAGTCTGGCTTAGCGAGGAGCCAGCAGAGCAGATGGGCTGGAAGTAAGGCAG CGTGCAATGAC---AAGCAGACTCCTAGCACACAGACAGAGCTATATAGGAGTGCTGGTCCCATGCACAGGAGAAAAGAA GTAAATAAGCTGAAATCTCCATGGTCTGAGAGTCCTGGAGCT---ACCCAAGAG---ATTCCTTGGATAACACTGAATAG TAGCATTCGGAAAGTTAATGAGTGGTTTTCCAGAAGTGATGGCCTG---------GATGAGTCACATGATGAGGGGTCTG AATCAAATGCAGAGGTTGCTTGTAAATTCGAATTTCCCAAG------GAAGTACAAGGATATTCTAGTTCTTCAGAGAAA ATGGACTTAATGGCCAATGATCCTCATGATGCTTTAATATGTGAAAATGAGAGAATCCTCTCCAAACCAGCTGTAAGTAA C---ATTGAAGATAAAATTTTTGGGAAAACCTATCGGAGGAAGACAAGTCTCCCTAACTTGAGCCATGTAACTAAAGACC TAATGATAGGAGCTGTTGCTACAGAAGCTCAGATGGCACAA--------------------------------------- ---------------------GAACGTCCTCTTACAAATAAATTAAAGCGCAAAAGGAGA---ACCTCAGGCCTTCATCC TGAGGATTTTATCAAGAAAGCAGGCATGAAAGTTGTTCAAAAGACTCCTGAAAAGATAAATCAAGAAACTAACCAAATGG AGCAGAAT---------GATCAAGTGAGGAATATTGTTGATGGTGGTCATGAAAATGATACAAAAAGTGATTAT---GTT CAGAAAGAGAAGAGTGCTAACCCAGCCAAA------TCATTGGCAAAAGAGTCCGCTTTCACAACTAAAGCGGAACCTAT AAGCAGTAGTATAAGCAATATGGAACTAGAATTAAATATGTACAATTCTAAAGCACTGAGGAAGAATAGGTTGAGGAGGA AGTCCTCTTCCAGGCATATTCACACACTTGACTTGGTAGTCAATAGAAATCCAAGTCCACCTCCTTACACTGAACTACAG ATTGATAGTTGGCCTAGCAGTGAAGAA---ATAAACGAAACA---AGTTCTGAACAAAAGCCAACCAGACACAGCAGAAA CCTTCACCTCATGAAAGAACAGGAAACTGCAACTGGAACCAAGAACAGTAACAAGCCAAATGAACAAATAAGTAAAAGAC ATGCCACTTACACTTTTTCAGAACTAAACATAACAAATAGAACTGACTTTATTACTAACTGCCCACGTTCTGATAATCTT CAAGAACTTGTCAATCCTAGCCTTCAAGGAGAGGAAAGGGAAGAGAAA---TCGGAAACAATGCAAGTATATGATAACAC CAAAGAACCTGAGGATCAGGTGTTAAGTGGAAGAAGG---GATTTGCAA---ATGGAAAGATCTGTTGAGAGTACCAGTG TTTCAGTGATACCCGATACTGATCATGGCACTCAGAACCACACCTCATTACCGGAAGCTGGCACCCTCGGG---AAGGCA GAA---ACAGCACCAAATCAATGTACAAGTCAGTGTAAAGCAATTGAAAATCCCAACCAACTTATCCATGGTTGT---CC T---------AGAAATGACACAGAGGGCTTTAAGGATCTATTGAAACATGAAGTTAAA---CACAATCAGGAGACATGCA TAGAAATGGAAGAGGGTGAGCTTGATATTCAGTATTTACAGAATACATTCAAGGTTTCAAAGCGTCGGTCATTTGCTCTG TTTTCAAATCCA---------GAAAAGGAATGTGCAACAGTCAGTGCCCACTCTAGGTCCTTCAGGAAACAAAGTCCAAA AGCCACTCTTGAATGTGGCGAAAAAGAAGAAAATCAGGGGCACAAAGAGTCTAAAGTCAAGCATGTACAGGCAGTTCATA CAAGTGTGGGCTATCCTGGACTCTGTCAGAAAGAGAAG---CCAAGTGATTATACCAAAGGTAGCATTCAGGGGGCCTCT AGGCTTCATCAGTCATCTCAGTTCAGT---GGCAATGAATCTGAACAAATTACTGCAAATGAAAATGGAATTTCACAAAG CCCAGATCAAACAGCATTGCTTTCT------------------------AAATGTAAGAAAAAC---TTGTCTGAAGAAA GATTTGAAGAACGTGCAGTATCACTCGAAAAAGCAGTGGGAAATGAGAGCATCATTCAAAGTACAGTGAGCACAGTTAGC CACAATAACATTAGGGAAAGGGCTTTTAAGGAAACCAGCTCAAGTAGTACTAATGAAGTAGGTTCCAGTATTAATGAAGT AGGTTCTAGT------------------------------------------AACGAAAACATCCAAGCAGAGGTAGGTA GGAACAGAGGACCTAAGTTAAATGCTATGCTCACATTAGGTTTTATGCAACCTGAAGTCTATAAACAAAATCTT---ACT CTAAGTAATTGTAAACATCCTGAAATAACAAAGCAGGGAGACAATGAAGAAAGAGTTCAAGCTGCTGACCCAGGTTTCTC TCCGTGTCTAATTTCAGATAACCTAGAACCA---CCTATGGGAAGTAATCATGCTTCTCAGATTTGTTCTGAGACACCTG ATGACCTGTTAGATGATGATGAAATCAAAGAAAATATCAGCTTTGCTGAAAGTGGCATTAACGAAAGATCTGCAGTTTTT AGTAAAGATGACCATAGAAGACAATTCAGAAGGAACCTAAGCCCTTTATCCCAT---TTAGGTTTGACTCAGGGTCACTT AAGAGGTACCAGAGAATTAGAGTCTTCAGAAGAGAACCTGTCTAGTGAG >Madagascar TGTGGAACAAATACGCTTGCCAACTCATTACAGCGTGAGAACTACAGTTTATTACTCACTAAAGACAGACTGAATGTAGA AAAGGCTGGATTCTGTAATGAAAGCAAACAGCCCGGCTTAGCAAGGAGCCAACATAACAGATGGGCTGAAAGTAAGGAGA CATGTAATGAC---AAGCCGACTCCTAGCACAGAGAAAAAGGTAGATAAGAATGCTGACCCCGTGCATGGGAGAAAAGGA GTGCCTAAGCAGAAACCTCCGTGCCATGGAAGTCCTAGAAAG---AGCCACGAT---GTGCCTTGGAAAACACGGAAGAG TAGCATTTGGAAAGTCAATGAGTGGTTTTCCAAAAGCGATGGCCTG---------GGTGACTCGCATGATGAGCGGCCTG AATCAGATGCAGACGTCGCTGGGGCCTTCGAAGTTCCAGAT------GAAGCACGCGAATCTTCTAGTTCACCAGAGAAA ACAGACTTGATGGTCAGTGATCCTCATGTTCCTTTACTGCCTAAAAGTGAAATAGTCCTTTCCAAACCAGTAGAAAGTAA C---ATCGAAGACAAAATATTTGGGAAAACGTATCGGAGGAAGTCAAGTCTCCTTAACTCGAGCCATGTAACCGAAGATC TAATGGTAGGAGCTGCTGCTGCTGTAGCACCTCCGATAGCG--------------------------------------- ------------------CAAGAGCACCTTCTTACCAGTAAATTAAAACGC---AGAAGA---TCATCCGTCCTCCACCC TGAGGACTTTATCAAGAAAGCAGATTTGGCAGTTGTTGAAAAG------------ATCAACCAGGGAACTGACCAAACAC GGCCGAAG---------GGTCAAGTGGAGCATACTCCCGATGGTGGTCACGGGCATGGAACAAAAGGCGGGAAT---TGT GTTCAGAAGGAGAGTGCTGACCTGGCAGAA------TCATCGGCCAAAGAATCTGCCTTTCGAACTGTAGCTGAGCCTTT GAGCAGTAGGAAAAGCGGTATGGAACTGGAACCGACTGTGTTCAATGCAAAAGCACAN---AAGAACAGGCTGAGGAGGA AGCCCTCTGCCAGGCACATCCACCCCCTGGAACTA---GTCAACAGACAGCCAAGCCCGACGAGGCACACAGAACTGCAA ATCAGTAGCTGGCCTAGCAGTGAAGAG---CTAAAGAAAGAA---GAATCTGAGCCAAAGCCAGTCAGACGGAGCCGGAA CTTACAGCTCACGAAAGACCAAGAAATGGCCATCGGAGCCAAGAAGAATGACAAACCAAATGAAGAAAGGGGCAAAAAAC ACGCCCCTGACACTTTCCCAGAACGAAATTTAACAGACACAACTGACCTAATTACTACCTGTTCGTTTTCTGGTAATCTT CAAGCATCTGTCTGTCCTAGCCTTCCAGGGGCAAACCTGAAAGAGAAA---CTGGGAACAGTGCAGGTGTCTAATGGTAC CAGAGACCCCAAAGGTGAGGTGTTGGGTAGAGCAAGG---GGCCTGCAA---ACCGCAAGATCTGTTGAGAGTACCAGTG TTTCACTGATACCTGATGCTGATGATGGCCCTCAGGGTACCATCTCAATCATGGAAGCAGGCAACCGAGGG---GAGGCA CAA---ACAGCACCAGGTGAATGTGCAAGGCAGTGTGCAGCAACTGAAAACCCCAACAGGAGTGTCCAGGGTCTT---TC CAAAGACACTAGAAATAACAGGGAGGGCTCTGAGGATCTCTTGACACACGACGTTAAC---CACCTTCAAGAGACATGCA CAGAAATGGAAGAGAGTGAACTTGATATTCAATCCTTACAGAATACATTCAAAGTCTCAAAGCGTCAGTCATTTGCTCTG TCTTCAAATCCA---------GAAAAGGAGTGTGCCTCGCTCGGTGCCCGCCCT---------------------CCAAA CATTGCTCTTGAGTGTGGGGAA---GAAGGGACTGAGGAGAACAAAGAGTCTGCAGTTCGACCTGTGCAGGCAGTTCCTG CAACTGTGGGCGGTGCTGGAGGTAGTCCAACAGAGCAACAGCCACGTGATTATACCAAAAGTCACCTTCAAGGAGTGTCC AGGCTTGGTCAGGCAGCTCCATTCAGA---GGCAGTGAATCTGACCCCAGTACCTCAGTTGAACATGGGATTGTGCAGAC CTCGGAGCNTGCCCCACCACTCGCTCCCATCAGGTCATCTGTTAACAGTGAACGTAAG------------------GAAA GACTGGAGGATCATGCAGAATCACTTGAAAGAGCCTCAGAAAACGAGAGTATCATTCCAAGTACAGTGAGCACAATTAGC CAAAATACCCCGAGAGAAAATGCTTTCAAAGGAACCAGCTCAAGCAGTCTTAATGAAGTAGGTTCTAGC----------- ----------------------------------------------------AGCGAAAACATTCAAGCAGAGCTAGCTA GGAACAGAGAACCTAAATTGGATGCTGTGCTCAGGTTGGGTCTTGTGCAACCTGAAGTCTGTAAGGAAAGTCTT---CCT ATGAGGAAATGTAAGCATTCTGAAGTAAAAAGGCAAAAAGGCAATGGAGGACTAGTTCCAGCTGTTCATCCAGATTTCTC TCGCTATCTAATGTCACATAACCCAGAGCAG---CCTATGGAGGACAAT---GATCCTCAGATTTGTTCTGAGACACCTG AAGACCTGTTAGATGACAGTGAAATAAATAAAAACAGCCACTTGGTTCAAAGTGACATTAGGGAAAGATCTGCTGTTTTT AGCAAAGATAACCAGAGAAGAGATTTCAGAAGGAGCCCTGGGCCTACATCCCAT---TTAGGTTTGTCTTGGGGTCACCC NAGAGGTGCTGAAGAGTTAGAGTCCTTAG-------------------- >Tenrec TGTGGCACACGTACGCTTGCCAGCTCGGCACAGCGCGAGGACTGCAGCTTATTACTCACCGAAGACAGACTGGATGGAGA AAAGGCTGGATTCTGCAAGGAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAGCATAGCAGATGGGCTGAAAGTAGGGGAA CGGGTAATGAC---AAGCCGACTCGTAACACAGAGGAAGAGGTAGTTGTGAGCGCTGACTCCGCGCATGGGAGGAAAGGA GTGTCTAAGCAGAAACCTCCGCGCCAGAAAAGGCCCAGAAAG---AGCCATGAT---GTGCCTTGGAAAACACGGAAGAG CAGCATTTCGAAGGTTAACGAGTGGTTTTCCAAAAGCCACGGCCTG---------GGTGACTCTCGCGATGGGCGGCCTG AGTCAGGCGCAGACGTAGCTGTAGCCTTCGAAGTTCCAGAC------GAAGCATGTGAATCTTATAGTTCTCCAGAGAAA ACAGACCTGATGGCCAGGGACCCTCCTATTCCCTTACTGCATAAAAGCGCAAGAGTCTTTTCCAAACCAGTAGAAAGTAA C---ATCGAAGACAAAATATTTGGGAAAACGTATCGGAGGAAGTCAAGCCTCCTTAACTCGAGCCATGTAACTGAAGATC TGGTGCTAGGAGCTGCGGCTGCCGTAGCGCCTCCGGTAGCA--------------------------------------- ------------------CAAGAGCAGCTTCTTACCAGTAAATTAAAGCGCAAGAGGAGA---TCCTTCGTCCTGCACCC TGAGGACTTCATCAAGAAAGCAGATTTGGCTGTCGTTCAAAAGACTCCTGAAACGATCCATCAGGGACCTGACCCAATGC AGCCGAAG---------GGGCCAGTGCAGAAGATTCCCGATGGTGGTCCCGGGCGAGGGACAAAAGGCGGGGATCGTGTT CCGAAGGAGAAGAGTGCTAACCTGGCAGAA------ACATCGGCCAAAGAATCTGCCTTTCGAACTGTAGCTGAACCTTT GAGCAGCCGGAAAAGCAGTATGGAACTGGAGTTGCCTGTGTTCAGTTCAAGAGCGCAG---AAGAACAGGCTGAGGAGGA AGCCCTCTGCCAGGCACATCCATCCGCTGGAACTA---GTCAACAGACAACCAAGCCCGACTACGCACACGGAGCTGCAA ATCAGCAGTTGGCCTAGCAGTGAGGAG---CTAAAGAAAGAA---GAATCCGAGCCAAAGCCAATCAGACGGAGCCGGCA CTTAAAGCGGGAAAGA---------------------GCCAAGAAGAATGACAAGCCAAACGGAGAAAGGGGCAAAAAAC ACGCCCCTGACACATTCCCAGACCGAAAGTCAACAAGCACAACGGACTTAATTGCTAACTGTTCCGTTTCTGGCAGTCTT CATGGAGCTGTCTGTCCTGGCCTTCCAGGGGCAAAGCAAACAGAGAAA---CGGGGAGCAGTGCAGGTGTCTAATAGCGC CAGAGACCCCAAAGATGAGGTGTTGGGTAGAGCAAGG---GGCCTGCAA---ACTGCAAGATCTGTTGAGAGCACCAGTT TTTCACTGATACCTGCTGCTGCTGACGGCACCCCGGGTGGCGTCTCAATAATGGAAGCAGGCAGCCGAGGA---CAGGCA CAA---ACAGCACCAGATCCATGTGCAAGGCAGTGTACAGCAACGGACAACCCCAGCGAAAGTGCCCACGGTCTT---TC CAGAGATACTAGAAACAGCACGGAGGGCTTTGCGGATCTATTGACACATGGCGTTCCC---CACATCCAAGAGACATGCA CAGAAATGGAAGAGAGTGAACTTGATATTCAGTCTCTACAGAATATGTTCAAAGTCTCCAAGCGTCAGTCATTTGCTCTC TCTTCAAATCCA---------GAAAAGGAGTGTGCCACACTCTGTGCCCATCCTAGCGCCTTCAGGAAACAGAATCCAAA CGATGCTCTTGAGGGTGGAGAA---GAAGGGACTCGGGAGAACAAAGAGTCTACAATTAAGCCTGTGCGGGCAGTTCATA CCACCGTGGGC------------------ACGGAGAAGCAGCCAAGTGATTACACCAACAGTAGCTTTCAAGGAGTTTCT AGGCGTGGTCAGGCATCTCAATTCAGA---GCCAGTGAATCTGACCCCGGTACCTCAGTCGAACACGGAAGTTTGCAAAC CACAGAGCATACCCCACCACTCTCTCCCATCAGATCCTCCCTTAAAAGTAAATGTAAGGAAAAG---CTGTCAGAAGAAA GATTGGAGGATCAGGCAGAATCCCTTGAAAGAGCCTCGGGGAATGAGAGCATCATTCAAAGTACAGTGAGCACAATTAGC CAAAATACGCTTAGAGAAAATGCTTTTAAAGGAACCAGCTCAAGCAGTCTTAATGAAGTAGGTTCTAGC----------- ----------------------------------------------------AGCGAAAACATTCAGGCAGAACTAGCTA GGAACAGAGAACCTAAATTGGATGCTGTGCTCAGACTAGGACTTGTGCAGCCTGAAGGCTGTAAGGAGGAAAGTCTTCCC CTAAGGAAATGCAAGCATCCTGAAGTAAGAAGGCAAAAAGGCAATGGAGGACTAGTTCCAGCTGTCAATCCGGATCTCTC CCGCTATCTAATGTCACGTAACCCGGAGCAA---CCGATGGAGAGCAAC---GGTTCTCAGATTTGCTCGGAGACACCTG AAGACCTGTTAGATGACAGTGAAATAAAAAATAACAGCTACTTTGTTCAAAGTGACGTTAAGGAAAGGTCTGCAGTTTTT GGCAAAGATAACCAGAGAAGAGATTTCAGAAGGAGCCCTGGGCCTACATCCCAT---TTAGGTTTGACTTGGGGTCACCC AAGGGGTGCGGAAGAATTAGAGTCCTTAGAAGAAAGCGAAGCCAGTGAG >LesserEle TGTGGCACAGATCCTCATGCCAGCTCATTACAGCATGAGAGCAGCAGTTTATTACTCACTAAAGACAGAATGAATGTAGA AAAGGCTGAATTCTATAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAACAGAGCAGATGGGCTGAAAGTAAGGAAA CATGTAATGAT---AGGCAGACTCCTAGCACAGAAAAAAAGGTAGCTGTGAGTGCTGATCTTTATTATGGGATAAAAGAA GTGAATAAGCAGAAATCTCCGCACTCTGAGAGTCCAAACAAT---AACCAGAAT---ACTCCTTGGATGACATTGAACAG TAGCATTCGGAAAGTTAATGACTGGTTTTCCAGAAGCGGTGGCCTG---------GATGGCTGCCATGAT---AGATCTG AATCGAATGTAGTAATAGCTGGTGAAGTGGAAGTTCCAAAT------GAAGTACACGGATATTCTATTTATTCAGAGAAA TTAGACTTAATGCCCAACAATCCTCATGATACTTCACTGTATGAAAGTGAAAGAACCCTCTCCAAACCAGCTGAAAACAA C---ATTGAAGATAAAATATTTGGGAAAACCTATCGGAAGAAGGCAAGTCTCTCTAACTTGAGCCATGTGACTCAAGATC TCATTACAGGAGCTGTTGCTACAGAATGTCAAACAGCACAA--------------------------------------- ---------------------GAACGCCCTCTTACAAATAAATTAAAGCGTAAAAGAAGA---ACATCAGGCCTTCAGCC TGAGGATTTTATCAAGAAGGTAGATTTGACAGTTGTTCAAAAGATTCCTGAAAAGACAAATCAGGAAACTGAACAAATGG TGCAGAAT------GGTCAAGTGAAGAATAAGATTGCTAGTGGTGGTCATGAGAGTGATACAAAAGGTGATTAT---GTT CAGGAAGAGAAGAATACTAACCCAACAGAG------TCACTGGTAAGAGAATCTGATTTCAGAAATAAAGCTGAACCTAT AAGCAGCAGTATAAGCAAAATGGAGCTAGATTTAAATACACACAGTTCGGTAGCACCAAAGGAGAACAGGCTGAGGAGGA TGTCCTCAACCGGGCATGTTCACGCACTTGAACTAGTAGTCAATATAAGTCCAAGGTCACCTATCCATACTGAAGTACAG ATTGATGGTTGGTCTAGCAGTGAAGAG---AAAACGAAAAAA---CATTCCGAGCATAAGCCAGTCAGACCTAGCAGAAA CGTTTCAGTTACAACAAATCAAGAAACTGAAACTGGGTCCAAGAAGAATAACAAGCCAAATGAACAAATGAGTAAAAGAC ATGCCACTGACACTTCCCCAGGGCAC---------AACATAACTGGCTTCATTACTGACTGTTCAAATACCAGCAGTCTT CAAGAATGTTTTAATCCTAGACTTCAGGGAGAGGCAGTAGAAGACAAC---TTTGGACCAGTTCAAGTGTCTAATAGTAT CAAAGATCCCAAGGATCAAGTATTAAATAGAGGAAGG---AGTTTGCAGCACACTGGAAAATGTGTTGAGAGTACCAGTA TTTCAGTGTTATCTGATACTGATTATGGCACTCAGAATAGCATCTCATTACTGGAGGCTGGCACCCTAGGG---AAGGCA GAA---ACAGCACCAGATCAATGTGCAAGTCACTGTGCAGCAATGGAAAACTCCAAGAAACATGTTCATGACTTT---CC TAAAGATACTGGAAATGATACAAAGGGTTTAAAGGACTCATTGAAATGTGATGCTAGC---CACAGTAAGGATACGTACA TGGAAATGGAAGATAGTGAACTTGATACTCAGTATTTACAGCATACATTCAAGGTTTCAAAGCGTCAGTCATTTTCTCTG TTTCCAAATCCA---------GAAAGGGACTATACA-------------------------------------------- ----------------------------------------------------------AAGCTAGTGCAGCTAGTTCATA CCACTGCGAGCTATCCTGGAGCCTGTGAGGAAAAGAAA---CCAAATGATTTTACCAAATGTAGCATTAAAGGAGTCACT AGACTCTCTCATTCATCTCCATTGAGA---GGCAATGAATCTGAACTCATTACCGCAAATGAACATGAAATGTCACATAG CCCAGATCAGACACCGTCACTTTCTCCCACCAAGGTTCCTGTTAAAATGACATGGAAGAAAAACCACCTGTCAGAAGAAA ACTTTGAGGAACATACAATA------------ACAATGGGAAATGAGAGCATCGTTTATAGTCCAGTGAGCACAGTTAGC CAAAGTAATGTTAAGGGA------TATGCTCAGGCCAGTTCAAGCAGTATTAACGAAGTAGGTTCCAGTACTAATGAAGG AGGTTCCAGTATTAATGAAGTAGGTTCTAGT---------------------GGTGAAAACATCCAAGCAGAGCTCGATA GGAACAGAGGACCTGCATTAAATGCTGTACTCAGATTAGGTCTTGTGCAACCTGAAGTCTATGAACAAAGTCTT---CCT GCAGGAAATTGTAAACATCCTGAAATGACAAGGCCAGGAGACAGTGAAGGAGAAAAAAAGACTGTTAATCCAGATTTCTC TCCATGTCTACTCTCAGATAATTTAGAACAA---CCTAGGGGAAGTTGTCATGCTTCTCAGATTTGTTCTGAGACACCAG ATGACCTGTTTGGTGATGATGAAATAAAGGAAAATAGCAGCTTTGGTGAAATCAGCTTTAAAGAGAGATCTGCTGTTTTT AGTAAAGATGAGCAGGCCAGAGAGTTCAATAGGAACTCAAGCCGTTCATCTCGT---TCAGATTTGGCTCCCAGTCATCT AAGACGCGATAGGGAATTAGAGTCCTCAGAAGAGAATGTATGTA----- >GiantElep TGTGCCACAAGTATTCATGCCAGCTCATTACTGCATGAGAACAGCAGGTTATTGCTCAGTAAAGACAGAATGGATGTAGA AAAGGCTGAATTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGGAGCCAACAGAGCAGATGGACTGAAAATAAGGAAA CATGTAATCAT---AGGCAGACTCCTAGTATAGAGAAAAAATTAGATATGAATGCTGATCCCTCTTATGGGCGAAAAGAA GTGAATAAGCAGAAATATGAATGCTCTGAAAGCCCTCAAGAT---ACCCAAGAT---ATTCCTTGGATGACACTGAATAG TAGCGTTCAGAAAGTTAATGCATGGTTTTCCAGAAGTGATGGCCTC---------GATGATGCCCCTGATGTAGGGTCTG AATCAAATACAGCAATAACTGGTGCACTGGAAGTTTCAAAG------GAAGTACATGGATATTCTAGTTCTTCAGAGAAA GTACACACAATGACTGGTGATCCTCAGGGTGCTTCAGTATGTGAAAGTGAAAGAGTCTTCTCTAAACCAGCAGAAAATAA C---GTTGAAGATAAAATATTTGGGAAAACCTATCGGAGAAAGTCAAGTCTCCCTAACTTGAACCATATAACGCAAGATC TCATTGTAGGAGCTGTTGCTACAGGACCTCAGACAGCACAA--------------------------------------- ---------------------GAACACCCTCTTATAAATAAACTAAAGCGTAAAAGGAGA---ATATCTGGCCTTCGTCC TGAAGATTTTATCAAGAAGGTAGATTTGACT---AGTCAGAAGACTCCTGAAAAGAGAAATCAGACCATTTACCAAGTGG AC------------------------AGTAGTATTGCTGGCGGTGGTCATGAGCATGAAACGAAAGGTGACTGT---GTT CAGAAAGAGAAGAATGTTAGCCCAGCAGAA------TCATTGACAAAAGCTTCTGCTTTCAGAACTAAGGATGAACCTAT AAGCAGCAGTGTGAGCAGTATGGAACTAGAATTAAATATGTACAGTTCGATAGCACCAAAGAAGAACAGGCTGAGAAGGA AGTCCTCTACTAAGCGTATTTGTGCACTTGAACTAGTAGTCGATAGAAATCCAACTTCACCTACCCATGCTGAGCTAGAG ATTGATAGTTGGCCTAGCAGTGAAGAG---AGAAGGGAAAAA---TGTTCAGAGTTTAACTCCGTCAGACACAGCAGAAC CTTTCAGCTTATGAAAGGTCAAGAAACTGAAATTGGAGACCAAAAGAATAATGACAAGCAAAATGAACAAATAAGTAAAA AACATGCCACTGACACTTCTCCAAAACGA------AACATAACTGGCTTTATCACAAACTGTTCAAATACTGATAATCTT CAAGAATTTGTTAATCCTAGATTTGAAGGAGAGGAAATAGCC---------GTGGGACCAATTCAAGTGTTGAATAGTAC CAAGGACCCTGGAACTCAAGTGTTAAGTAAGGAAAGG---GGTTTGCAC---ACTGGGAATTATGTTGAGAGTACCAGTA TTTCAGTAATACCTGATACTGATGATGGTATTCAAAATAGCACCTCATTACTGGAAGCTGGCACATTAGAA---AAGGCA GAAGAAACAGCATTGACTCAATGTGCAAGTCACTGTGCAACAATTTTAAACCCCAACACACATGTTCATGGCTTT---CC TAAAGATCCTGCAAATGACACAGAGGGTGTTAAGGATCTGTTGAAATGTAATCCTAAC---CACCTTCAGGATACGTGCA TAGAAATGGAAGATAGTGAACTAGATACTCAGTATTTACAGAATACATTCAAAGTTTCAAAACGTCAGTCATTTACCCTG TTTCCAAATCCA---------GAAAAAGAATGTACAACAGTCTGTGCCCACTCCAGGCTCTCAAAGAAACAAAATCCAAG TGTCACTCTTGAGTGTAGAGAAAAAAAAGAAAATCAGGGGAATGAAGAGTCTAAAATGAAACATGTGCAGGTCGTTCATA CATCTGTGCACTATCCGGGAGTTTGTGAAGAAGAGAAGATACCAGATGATCACACCAAAGTTAGCATTAAAGGGATCTCT AGGCTTTGTCAGTCATCTCCTTTCAGG---AGCAATGAATCTGAACGCATTACTGAAAATGAATGTAAAATGTCACATAG CCCAAACCAGACACCATCATTTTCTCCCACCAAGCCATCAGTTAGAACCAAATATAAGCAATTCTACTTGTCAGAAGAAG AGTTGGAGGAACATGCACTATCACCTGAAAGAGCAATGGAAAATGAGAGTTTCATTCACAGTACAGTGAACGCAGTTAGC CAAAATAACCTTAGGGGAAGTGTCTTTAAAGAAGGCAGCTCAAGCAGTATTAATGAAGCAGGATCCAGTACTAATGAAGT AAGTTCCAGTATTAATGAAGTATGTTCTAGT---------------------GATGAAAACATCCAAGCCGAACTAGATA GGAACAGAAGACCTGAATTAAATGCTGTACTCAGGTTAGGTCTTATGCAACCTGAAGTGTATCAACCAAGTCTT---CCA ACAAATAACTGTGAATATCTTGAAATTAGTGGGCCAGGAAAAAATGAAGGCATAATTCAGGCTGTTAATCCAGATTTTAC TCCGTGTCTGATTTCAGATAACTTAGAACAACAGCCTATGGGAAGTAATCATGCTTCTCAGATTTGTTCTGAAACACCTG ATGACCTGTTAAATGATGAGAAAAGAAATGAGAATATCAGCTTTGCTCAAATCAGCATTAAGGAACGATCCACTGTTTTT AGTAAA---GACCAGGCAAGAGAATTCAGAGGAAACCCAAACCCTTTATCCCAT---TCAGATTTGACTCAGAGTCATCT AAGAAGTGGTAGGGAATTAGAGTCATCAGAAGANAA------------- >Caenolest ---------------------NGCTCATTACTGCCTGAGATCACCAGTTTATTGCCCAACACAGACAGAATGAATGTAGA AAAGGCTGAACTCTGTAATAAAAGCAAACAGCCTGGCTTAGCAAGCAACCAGCAGAGCAATCTGGATGAAAGTAAGGAAA TATGTAGTGCTAGCAAGACCCCAGGTGCAGAGGAA---CAGCCTGAGCTGAATGCCAATCATCTGTGTGAGAGGAAAGAA CTAGAGGAG---AAGCTGCAGTGCCCTGAGAGCCCCAGAGGTGATTCTGGGGACTGCCTGTCTGGAACCAAAGTGAAAAA CAGTATTCAGAAAGTTAATGAGTGGTTATTCAGAAGTAATGACGTTTTAGCCCCAGATTACTCAAGTGTTAGGAGCCATG AACAGAATGCAGAGGCAACCAATGCTTTAGAATATGGGCATGTAGAG---ACAGATGGAAATTCTAGCATTTCTGAAAAG ACTGATATGGTGGCTGACAGTACTGATGGTTCCTGGCTACATGCACCTGAAAAAAACTGCCCCAGACCGGCAGAGAGCAA CAATATTGAAGATAAAATATTTGGAAAAACCTATCGAAGAAAGTCGGTTCACCCTGTTTTGAATTACGTAACTGAAAACT TGATTGTTGAAACCATTGCTCCTGATTCTGTGATCCCTCCA--------------------------------------- ---------------------GAGCCTCTCAAAAAAACCAAATTAAAGCGTAAAAGAAAGACCATATGTRACCTGCAGCC TGAGGATTTCATCAAAAAGACAAACATTCCAGTTATTCCCAAAACCCCTGAAAAGAAAAATCACCCTGTTGACCAGATCC TTGAAAAAGAACAAAATGGCCAGGTGATGAGCACAGCTGATGGTCAGTCCAAGCAGAAAGCACCCGGTTGTCAT---GTG GGGGAACTGAAAGAGGCTCAGGCATCAGAACCATCCTCTGTAGAGAAAGGATCCACTTTCAAAACTGGATCCGAGCCTGC AGCTGGTAGCACAAACCAGAGGGAACTTGAATTAAATGGTAGAGATGCAAAAATGACAAAAAAAGACAGACCAAGGAAGA GGCCTTCAGTTAGGACTGTCTGTGCTCTGGAGCTCGTGACTGATAGACACCCAGGCTCTTCTAATGAGACAGAACTACAG ATCGATAGCTATCCCAGCAGTGAAGAG---ATAAGGAAAGGAAATAATTCTGAGCAAAAGCAAGTCAGACGCAGCAGAAG ACTTCAGATGCTGTCAGAA---GAAATTGCAGCAGGAGCCAAGAAGGCCCATAAGCCAGATGAAGAAGTGGAAGAGAATT GTGTCAATGAAGTTTCCCCAGAACTAAAAATAGGAAAAGTATCTGCCTGTTCTACTGACAGTCTAGCTACTGATAGTGAT CTGGTATTAGCTAGCTGCAGTTTCACAGAA---GGAGATGAAAAGAGC---CTGGAAGCCTTCCAG---------CCCAG CAGAGACCAAGAC---AGCCTGGCAGTAAGCAGAGGAGAGAAGTTGCAA---GGGAAAAGAACCAAAGGAAACATGGAGG TTTTGGAGGTTGCCAGTACTGATTGGGACACTCAGGACAGCACCTCATTGTTTCCAACCGATGTTCCCCCA---AATCCA ACA---GCAGACTCTGGCCCACACAGAAATCAACATGAGGTCATAGAAACCCCCAAGGAACTCTTTGATGATTGCTCATC CAAAAACACCGGAAGTGGTAAAGAAGATTTG---------ACAAGACAAGAAGTCAAA---AATACCTCAGAGACAACCA CAGAGATAGAGGACAGTGAACTTGATACCCAATATTTACAGAATACCTTCAAACGTTCAAAACGCCAATCATTTGCTCTG TGTCCCAGTCCAAGG------CAGACAAGTATGAAACTCCGGTCCATCCCTAGAGCTCTAAGTCATCAGAGCCCAGATAA AGCCACGAATCATGGGGGGCAGGAAAAAAAAAAGCAGGGAAGCAGAGAATCAGACAAGGCTGTGCAGCCAGAACTTGCAG TCATGAGTTCAGCTGCGGTTTGTCAGACAAAGGAGAAAAAGCCAGGTGATTATGCCAAATGTAGCACA------GTCTCT AGGCTTTGTCACATAGCTCCATTACATGATGACAATGACTGTGACCACAGTGCTGAAAACAACAAGGGAATTTCACAAGT TCCTGATCAAAAGCAATCTGTCTCTCCAGCAAAGTCATCAGCTGGTAGATCTATATACACAAAAAGCCTCCTGGAGGAAA GACTTGATGAACAGACCACATGTCCCGAAACAGTGATGGGAAATGAAAGCTTAGTCCACAGTAGCTTAAGCCTGGTTAGC CAAAGTAACAGCGGAGAATATATTTCTAAAGCAACTGACTCAAACAGATTTGTTGGTGTAGACTCTAGC----------- ----------------------------------------------------GGAGAAGGTAGTCAGGAAGAAAAAGGTG AAAACAAATTAAATCAGTCCCAAGTCTGTCAACAAAGCTT---------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ------------------------------------------------- >Phascogale ---------------------NGCTCATTACTGCCTGAAACCTCCAGTTTATTGCCCAACACAGACAGAATGTCT---GA AAAAGCTGAGCTCAGTAATAAAAGCAAACAGTCTGGCTTAGCAAGGAACCAACAGAGCAGACTGGATGAAAGTAAGGGAA TATGTAGTACTGGGAAGACCCCCAGTGTAGGAGAG---CAGCCTGAGTTGAATGCCCATCATCTGTGTGAGAAGCAAGAA CTAAAGGAG---AAGCCACAAGGTCCTGAAGGCCCCAGAGGAAATCCTCAGAATTGCCTATCTGGAACCAAACTGAAAAG CAGTATTCAGAAAGTTAATGAGTGGTTATCCAGGAGTAATGACATTTTAGCCTCCGATTGCTCCCTTGACAAGAATCATA AGCAGAATGCAGAGATAGCTAGTGCCTTAGAAGATGGGCATCCAGATAACTCTGATGGAAATTCTAGCATTTCTGAGAAG ACTGACGTTGTGGCTGACACTGCCGATGGAGCCTGGCTACATGTGCCTAAAAGAACTTACACCAGGCCAGCAGAAAACAA CAATATTAAAGATAAAATATTTGGAAAAACCTATCGGAGAAAGTCGGGTCACCCTAATTTGAATCACATAACTGAAAATT TGATTGTTGAGACAGTTGTTCCTGATTCTTTGGTTCCTCCA--------------------------------------- ---------------------GAACCTCTGAAAAATACCAAGTTAAAGCGTAAAAGAAAGACTATATGTGACTTGCAGCC TGAGGATTTCATTAAGAAGACG---GTTCCAGTTACTCACAAAACCCCTGAAAAGAAACATCACGCTGCTGACCAAACCC TTGAAAGAGAACAAAATGACCAAGTGATGAACATGGATAATGGTCATCCTGAACAGAAAGCACTAAATGGTCAT---GTA GGGGAAATTAAAGAAGCTCAGACATCGGAACTGTTCTCTGCAGAGAAAGAATCCACTTTCAGAACTGGAACAGAGCCTGC AGCTAGC------------------------TTAAATGGTGAAGAAACCAACATAACAAAAAAAGACAAGCTGAGGAAGC AGCCTTCATTCAAGATTGTCTGTGCTCTTGAGCTTGGAGTTGATGGAAGCCCAAGCTCTTCTAATGAGACTGAACTACAG ATCGATAGCTATCCCAGCAGTGAAGAG---ATAAGGAGAAAAAATAATTCTGAACAGAAGCAACTTAGACGCAGCAGAAG ACTTCAGCAGGTGTCAGAA---GAGATTGCAATTGGAGCCAAGAAAGCCCATAAGCCAGATGATCAAGCAGAAGAAAGTT GTATCACTGAAGTTGTCTCAGAACTAAAATTAGGAAATCTACCTGCCTGTGCTCCTGACAATGTCAGTACTGATAAGGAT CAAGTATTAGCTAGTTGCAGTTTCACA------GGAGATGAAAGGAGT---CTGGAAGTAATCCCT---------AGCAG CCAAGACCAAGAT------TTGGCATTGAGTGGAAAGGAAGGGTTGCAA---GGTGAAATATCTCAAGGAAGCCTGGGGA CTGTGGAGGTTCCTGATACTGCTTGGGACACTCAGGACAGTACCTCGTTGTTTCCAGCTGATACTCCTCAA---AATTCA AAA---CCAGGTCCCAGTCCTCACAGAAATCACTGTGAAATAATGGAAACCCCCAAGGAACTCTTAGAAAGTAGTTCATC CAAAAACACTGAAAGTAGTGTAGAAGATTTAAGGAGCCTGATGAAACAAGAAGTTAAA---AATGCCTCCAAGACAATCA CAGAAATGGAGGATAGTGAACTTGACACCCAGTATTTACAGAATACTTTCAAGCGTTCAAAGCGCCAGTCATTTGCACTG TGTTCTAGCCCAAGG------CAAGAATATGTGAAAACCTGTGCTGTCCCTGGGGCTATAAGTCAGCAAAGT-------- ----ACAGTTCGTAGGTACCAGGAAAAAGAAAAGCAAGAAAACAGAGAATCAAACAAGCCTGTGCAGCCAAAGCCTGCTG TTGTG---------------------ATAGAGAAGGGGAAGCCAGGTGATCATGCCAAATGGAGCACCAGAGAAGTCTCC AGGCTTTGTCACATAGCTTCATTAAATAGTGGCAATGACTGTGAACCCATTGCTGAAATCAACCAGGGAATTTCACAAGT TCCTGATCAAAACCAATCAGTTTCTCCAGCAAGGTCATCTGATAGTAAAACCATATATGCAAAAAACTTCCTGGAGGAAA GGCTTGATGAGCAAACCACGTGCCCTGAAACAACTATGGGAAATGAAAGCTTAGCCCAAAGCAGCATTAGTTTAGTTAGT CAAAGTAATAGCAGAGAATATGTTTCTAACCCAATTGACTTAATT------ATCAGCGTAGGCTCCAGT----------- ----------------------------------------------------GGAGAAGGCACTCAGGCAGAAAAAAGTG AAAACAAAGAATCTGAATTAAATACACCACCCAAATTAAAGCTTATGCAACCCCAAGTCTCTCAACAGACCTTT---CCT CAGAATAATTGCAAA----------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ------------------------------------------------- >Wombat ---------------NNTGCCAGTTCATTACTTCCTAAAACCAGCAGTTTATTGCCCAACACAGACAGAATGAATGTAGA AAAGGCTGAACTCTGCCATAAAAACAAACAGCCTGCCTTAGGAAGGAACCAAGAGAGCAGTCTCGATGAAAGTAAGGAAA TATGTAGCCCTGGGAAGACCCCAGGTGCCTGTGAG---CGGCATGAGCTGAATGACCATCATCTGTGTGAGAGGCAAGGC CTAGAGGAG---AAGCCGCAGCACCCTGAGAGCCCTAGAGGTAATCCTCAGAACTGCCTGTCTGGAACCAAACTGAAAAG CAGCATTCAGAAAGTTAATGAGTGGTTATCCAGAAGTAGTGACATTTTAGCCTCTGATAACTCCAACGGTAGGAGCCATG AGCAGAGCGCAGAGGTGCCTAGTGCCTTAGAAGATGGGCATCCAGATACCGCAGAGGGAAATTCTAGCGTTTCTGAGAAG ACTGACCCAGTGGCTGACAGCACTGATGATGCCTGGCTACATGTGCCTAAAAGAAGCTGTCTCAGGCCTGCAGAAAAC-- -AATATTGAAGATAAAATATTTGGAAAAACCTATCGGAGAAAGTCAGGTCACCCTAATTTGAATTATGTAACTGAAAACT TGTTTGCTGAAGCTGTGGCTCCTGATTCCTTGATCCCTCTA--------------------------------------- ---------------------GAGGCTCCCAAAAACACCAGGTTAAAGCGTAAAGGAAGGAGCATAGCTGACCTGCAGCC TGAGGATTTCATCAGGAAGACGGACGTTCCAGTTATTCACAAAACCCCTGAAAAGAAAAATCACTCTGTTGACCAAATTC TCAAAAGAGAACAAAGTGACCAAGTGATGAACACGGCTAACAGTCTTCCTGAGCAGAAAGCCCTAGGTGGTCAT---GTA GGGGAAGTGAAAGATGTTCAGGTATTAGAGCTGTTCTCTGCGGAGAAAGAATCCACTTTCAGAACTGGAACAGAGCCTGT AGCTGGCAGCACAAACCATGGGGAGCTTGAATTAAATAGTAGAAATGCCAAAATGACAAGAAAAGACAGGCTGAGGAAGA AGCCTTCAGCCAGGATCGTCCGTGCTCTTGAGCTCGTAGTTGATAGAAACCCAAGCTCTTCTAATGAGAGTGAACTGCAG ATCGATAGCTATCCCAGCAGTGAAGAG---ATAAGGAAAGGAACTAATTCTGAACAGAAGCAAATCAGACGCAGCAGAAG GCTTCGGCTGCTATCAGAA---GAAATTGTGGTTGGAGCCAAGAAGGCCCATAAGCCAGATGACCAAGCAGAAGAAAGTT GTATCAGTGAAGTTTTCCCAGAACTAAAAATAGGAAACGTGCCTGCCTGTGCTACTGACAGTCTAACTACTGATAGGGAT CAAGTGTTAGCTAGCTGCAGTTTCACAGAAGAAAGAGATGAAAGGAGC---CTGGAAGCAATCCCA---------AGCAG CAAAGACCAAGAT------CTGCCCTTGAATGGAGGGGAGGGGTTGCAA---GGTGAAAGAGCCCCAGGAAGCCTGGAGG CTTTGGAGGTTCCTGATACTGATTGGGACACTCAGGACAGTACCTCATTGTTTCCAGCTGATACTCCCCAA---AATTCA AAA---GCAGGACCCAGTCCTCACAGAAGCCACAGTGAAATAATGGAAACCCCCAAGGAACTCTTAGATGGTTGTTCATC CAAAAACACTGAAAGTGACGAAGAAGATTTGAGGAGCCTGATGAGACAGGAAGTTAAA---AATGCCTCCAAGACAACCA CAGAAATGGAGGATAGTGAACTCGACACCCAGTATTTACAAAATACCTTCAAACGTTCAAAGCGCCAGTCATTTGCTCTG CGTTCTAGCCCAAGG------CAGGAATGTAGGAAACCCTCTGCTGTCCCTGGGACTGTAAATCAGCAGAGTCCAGATAA CACCACAGATTGTGGGGGCCAGGAAAAAGAAAAGCAGGGAAACAGAGAATCAAACAAGCCTGTGTGGCCAAAGTCTGCAG TCATGAGCTTAGCTGCGGCTTGTCAGACAGAGGAGAGGAAGCCAGGTGTTTATGCCAAATGTAGCACCACAGAAGTGTCC AGGCTTTGTCACATAGCTCCATTACATGGTGTCATTGACTGTGAACACATTGCTGGAAACAACCAGGGAATTTCGCAAGT TCCTGATCAAAAACCATCAGTTTCTCCAGCAAGGTCATCTGCTAGTAAAACTATAAATACAAAAAACCTCCTGGAGGAAA GGCTTGATGAACAGACCACATGTCCTGAAACAGCTATGGGAAATGAAAGCTTAGCCCAAAGCAGCTTAAGTCCAGTAAGC CAAAGTAATAGCAGAGAATATATTTCTAAAGCAACTGACTTAAATAGATTTATCAGCATAGGCTCTAGT----------- ----------------------------------------------------GGAGAAGGCAGTCAGGCACAAAAAGGTG AAAACAAAGAATCTGAATTAAATACACAACCCAAATTAAAGCTTGTGCAACCCCAAATCTGTCAACAAAGCTTT---CCT CAGGATAATTGCAAAGAGTCTAAAAGAAAAGGGAAGGGAGGAAATGGAAAATTAGCTCAGGCCATCAGTACAGATTCATC TCCATGTTTAGAACAA------------------ACTAAAGAGAGTACACATTCTTCTCAGGTTTGTTCTGAGACACCTG ATGACCT------------------------------------------------------------------------- -------------------------------------------------------------------------------- ------------------------------------------------- >Bandicoot ---------------------NACTCATTAATGCTTGAAACCAGCAGTTTATTGTCCAACATAGACAGAATGACTACAAA AAAGGCTGAACTCTGTAATAAAAGTAAAGATCCTGGCTTAGCAAGGAACCAACAGGACTGTTTGGGTGAAAGTAAAGAAA TAAGTAGCACTGTGAAGACCCCAGCTGCAGGGGAG---CAGCATAAGCTGAATGCCCACCATCTGTGTGAGAAGCAAGAA CTAGAGGTA---AAGTCACAGCACCCTGAGAGCCCCAAAGGTAGTCCTCGGAGGTGCCGGTCTGGAACCAAACTGAAAAG CAGTATTCAGAAAGTCAGTGAGTGGTTGTCTAGAAGTAATGACATTTTAAACTCTGATTATTCCCATGAGAGAAGCCAGG AGCAGAATGCAGAGATTGCTATTGCCTTAGAAGATGGGCATCTGAATACTGCTGATGGAAATTCTAGCATTTCTGAGAAG ACTGNCCTGGTGGCTGNCACCACTGAT---------------GTGCTGGAAACTAGCTTNTCCAGGCCAGCTAAAAGC-- -AATATTGAAGATAAAATATTTGGGAAGACCTATCGGAGAAAGTCANGTCACTCTAATTTGAATTATCTAACTGAAAACC TCCTTGTTGAAACTATTGCTCCTGATTCTTTGATCCCTCCA--------------------------------------- ---------------------GAATCTCTCAAGAACATCAAGTTAAAGCGAAAAAGAAAAACTATATCTGACCTGCAGCC TGAAGATTTCATCAGGAAGACAGATGTTCCAGTTAGTCACAAAACCCCTGAAAAGAAAAATCCTGCTGTTGACCAGATTC TTGAAAGAGAACAAAATGACCAAGTGATGAACACAGCTAATGGTCATCTTAAACAGAAAGCACTGGGTGATCAT---GTC AAGGAAGTGAAAGATGCTCAGGCAGCAGAACTGTTCTCTACAGAGAAAGAATCAACATTCAGGACTAGAACAGAGCCTAA AGCTGGCAGCATAGTCCACGGGGAGCTCGAATTAAATGGGAGAGGTGCCAAAATGACAAAAAAGGACAGGTTGAGGAAAA AGCCTTCAGCCAGGATTGTCCGTGCTCTTGAGCTTGTGGCTGATAAAAACTCAGGCTCTTCTAATGAGGCTGAATTACAG ATCGATAGTTATCCCAGCAGTGATGAG---ATAAGGAAAGGAAATAATTCTGAACAGAAGCAAATCAGACGCAGCAGAAG ACTTCAGCTACTGTCAGAA---GAAATTGCAGTTGGAACCAAGAAGGCCCATGAGCCATATGACCAAGCAGAAGAAAGAT GTGTCAAGAAGGTTTTCCCAGAATTGGAAATGGGAACTGTGTCTGCTGGTGCTACTGACAGCCTATCTACTGATAGGGAT GAAGTGTTAGCTAGTTGCAGTTTCACAGAT---GGAGAGGAAAGGAAC---CTGGAAGTAATCCCA---------AGCAG CAAAGACCAAGACCAAGATCTGGCATTAAGTGAAAGGGAAAGGTTGCAA---GAAAAAAGAACCCAAGGAAACCTGGAGC TTCTGGAGGTTCCAGATACTTATTGGGAAACTCAAGACAGTACTTCACTGTTTCCAGCTGAAACTCCCCAG---AATTCA AAA---GCAGGACCCAGTCCTCACAGAAGTAACTGTGAAATAATGGAATCCTCCAAAGAACTCTTCGATGCTTATTCATC CAAAAACACTGACAGTGGCACTGAAGGTTTG---------ATAAGACAGGAAATTAAA---TATGGCTCTGAGACATCTT CAGTAATGGAGGATAGTGAACTTGACACCCAGTATTTGCAGAATACCTTCAAACGTTCTAAGCGCCAAACATTTGCTCTG TGTTCCAACCCAAAG------CAGGAACAGATAAAACCCTGCTCTGTTCCTAGGGCTGTCAGCCACCAGAGTTCAGATAA TGCCTCAGACTGTGGGGGCCAAGAAAAAGAAAAGCAAGGAAACAGAGAATCAAATAAACCTGGCCAACTAGCATCTGCAG TCAGGAGCTCAGCTGCCACTTGTCAGACA---GAGAGGAAGCCAGGTGATCCTGACAAATGTAGCGCCACAGGAGTTTCC AGACTTTGTCACATAGCTCCATTACAAGAAGGCAATGACTGTGAATACATTGCTGGAAAAAAACAGGGAATTTCACAAGT TCCTAATCAAAAACAATCAGTTTCTCCGACAAGGTCATCAGTTAGTAAA---ATATATACAAAAAACCTCTTGAAAGATA GACTT---GAACAGACCACATGCCCTGAAACAGTTATGGGAAATGAAAGCTTAGGCCAAAGCAGCTTAAGTCCAGTTAGC CAAAATAACAGCAGAGAATATATTTCTAAAGCAACTGACTTAAATAGATTTATTAGCAGGGACTCTAGT----------- ----------------------------------------------------GGAGAAGACAGTCGGGCAGAAAAAGGTA AAATCAAAGAATCTGAATTAAATACACCAACCAAATTCAAACTTGTGCAACCACAAGTATGTCAACTAAGCTTT---TCT CAGGATAATTGCAAAGAGCCAAAAAGAAAAGGGAAAGGAGGAAATGGAATATTAGCTCTGGCCACCAGTACAGATTCATC TCCATGTTTAAAAGAA------------------ACTAAAGAGAGTACACATTCTTCTCAGG------------------ -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- ------------------------------------------------- iqtree-piqtree-b8a3d6a/tests/data/protein.fasta000066400000000000000000000031111521173175100217160ustar00rootroot00000000000000>Seq1 LYLIFGAWAGMVGTALSLLIRAELGQPGTLLGDDQIYNVIVTAHAFVMIFFMVMPIMIGGFGNWLVPLMI GAPDMAFPRMNNMSFWLLPPSFLLLLASSTVEAGAGTGWTVYPPLAGNLAHAGASVDLAIFSLHLAGVSS ILGAINFITTAINMKPPTLSQYQTPLFVWSVLITAVLLLLSLPVLAAGITMLLTDRNLNTTFFDPAGGGD PVLYQHLFWF >Seq2 VGTALXLLIRAELXQPGALLGDDQIYNVVVTAHAFVMIFFMVMPIMIGGFGNWLVPLMIGAPDMAFPRMN NMSFWLLPPSFLLLMASSTVEAGAGTGWTVYPPLAGNLAHAGASVDLAIFSLHLAGISSILGAINFITTA INMKPPALSQYQTPLFVWSVLITAVLLLLSLPVLAAGITMLLTDRNLNTTFFDPAGGGDPVLYQHLFWFF GHPEVYILIL >Seq3 LYLIFGAWAGMVGTALSLLIRAELGQPGALLGDDQVYNVVVTAHAFVMIFFMVMPIMIGGFGNWLVPLMI GAPDMAFPRMNNMSFWLLPPSFLLLLASSTVEAGVGTGWTVYPPLAGNLAHAGASVDLAIFSLHLAGISS ILGAINFITTAINMKPPALSQYQTPLFVWSVLITAVLLLLSLPVLAAGITMLLTDRNLNTTFFDPAGGGD PVLYQHLFWF >Seq4 WAGMVGTALSLLIRAELGQPGALLGDDQIYNVVXTAHAFVMIFFMVMPIMIGGFGNWLVPLMIGAPDMAF PRMNNMSFWLLPPSFLLLMASSTVEAGVGTGWTVYPPLAGNLAHAGASVDLAIFSLHLAGISSILGAINF ITTAINMKPPALSQYQTPLFVWSVLITAVLLLLSLPVLAAGITMLLTDRNLNTTFFDPAGGGDPVLYQHL FWFFGHPEVY >Seq5 LYLIFGAWAGMVGTALSLLIRAELGQPGALLGDDQVYNVVVTAHAFVMIFFMVMPIMIGGFGNWLVPLMI GAPDMAFPRMNNMSFWLLPPSFLLLLASSTVEAGVGTGWTVYPPLAGNLAHAGASVDLAIFSLHLAGISS ILGAINFITTAINMKPPALSQYQTPLFVWSVLITAVLLLLSLPVLAAGITMLLTDRNLNTTFFDPAGGGD PVLYQHLFWF >Seq6 WAGMVGTALSLLIRAELGQPGALLGDDQIYNVVVTAHAFVMIFFMVMPIMIGGFGNWLVPLMIGAPDMAF PRMNNMSFWLLPPSFLLLMASSTVEAGVGTGWTVYPPLAGNLAHAGASVDLAIFSLHLAGISSILGAINF ITTAINMKPPALSQYQTPLFVWSVLITAVLLLLSLPVLAAGITMLLTDRNLNTTFFDPAGGGDPVLYQHL FWFFGHPEVY >Seq7 VGTALSLLIRAELGQPGTLLGDDQIYNVIVTAHAFVMIFFMVMPVMIGGFGNWLVPLMIGAPDMAFPRMN NMSFWLLPPSFLLLLASSTVEAGAGTGWTVYPPLAGNLAHAGASVDLAIFSLHLAGVSSILGAINFITTA INMKPPALSQYQTPLFVWSVLITAVLLLLSLPVLAAGITMLLTDRNLNTTFFDPAGGGDPVLYQHLFWFF GHPEVYILILiqtree-piqtree-b8a3d6a/tests/test_app/000077500000000000000000000000001521173175100201305ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/tests/test_app/test_app.py000066400000000000000000000117461521173175100223320ustar00rootroot00000000000000import pytest from cogent3 import PhyloNode, get_app, make_tree from cogent3.core.alignment import Alignment import piqtree from piqtree import ModelFinderResult, jc_distances, make_model def test_piq_build_tree(four_otu: Alignment) -> None: expected = make_tree("(Human,Chimpanzee,(SpermWhale,HumpbackW));") app = get_app("piq_build_tree", model="JC") got = app(four_otu) assert expected.same_topology(got) assert got.source == four_otu.source def test_piq_build_tree_support(four_otu: Alignment) -> None: app = get_app("piq_build_tree", model=make_model("JC"), bootstrap_reps=1000) got = app(four_otu) supports = [ node.support for node in got.postorder() if not node.is_tip() and node.name != "root" ] assert all(supports) def test_piq_fit_tree(three_otu: Alignment) -> None: tree = make_tree(tip_names=three_otu.names) app = get_app("model", "JC69", tree=tree) expected = app(three_otu) piphylo = get_app("piq_fit_tree", tree=tree, model="JC") got = piphylo(three_otu) assert got.params["lnL"] == pytest.approx(expected.lnL) assert got.source == three_otu.source @pytest.mark.parametrize("num_taxa", [10, 50, 100]) @pytest.mark.parametrize("tree_mode", list(piqtree.TreeGenMode)) def test_piq_random_tree(num_taxa: int, tree_mode: piqtree.TreeGenMode) -> None: app = get_app("piq_random_tree", tree_mode=tree_mode, rand_seed=1) tree = app(num_taxa) assert len(tree.tips()) == num_taxa def test_piq_jc_distances(five_otu: Alignment) -> None: app = get_app("piq_jc_distances") dists = app(five_otu) assert ( 0 < dists["Human", "Chimpanzee"] < dists["Human", "Dugong"] ) # chimpanzee closer than rhesus assert ( 0 < dists["Human", "Rhesus"] < dists["Human", "Manatee"] ) # rhesus closer than manatee assert ( 0 < dists["Human", "Rhesus"] < dists["Human", "Dugong"] ) # rhesus closer than dugong assert ( 0 < dists["Chimpanzee", "Rhesus"] < dists["Chimpanzee", "Manatee"] ) # rhesus closer than manatee assert ( 0 < dists["Chimpanzee", "Rhesus"] < dists["Chimpanzee", "Dugong"] ) # rhesus closer than dugong assert ( 0 < dists["Manatee", "Dugong"] < dists["Manatee", "Rhesus"] ) # dugong closer than rhesus assert dists.source == five_otu.source def test_piq_nj_tree(five_otu: Alignment) -> None: dists = jc_distances(five_otu) expected = make_tree("(((Human, Chimpanzee), Rhesus), Manatee, Dugong);") app = get_app("piq_nj_tree") actual = app(dists) assert expected.same_topology(actual) def test_piq_model_finder(five_otu: Alignment) -> None: app = get_app("piq_model_finder") got = app(five_otu) assert isinstance(got, ModelFinderResult) def test_piq_model_finder_result_roundtrip(five_otu: Alignment) -> None: app = get_app("piq_model_finder") got = app(five_otu) rd = got.to_rich_dict() inflated = ModelFinderResult.from_rich_dict(rd) assert isinstance(inflated, ModelFinderResult) assert str(got.best_aicc) == str(inflated.best_aicc) def tree_equal(tree1: PhyloNode, tree2: PhyloNode) -> bool: return str(tree1.sorted()) == str(tree2.sorted()) def test_piq_consesus_tree(five_trees: list[PhyloNode]) -> None: app_majority = get_app("piq_consensus_tree") app_strict = get_app("piq_consensus_tree", min_support=1) app_0_3 = get_app("piq_consensus_tree", min_support=0.3) expected_majority = make_tree("((a,b),(((e,f),d),c))") got_majority = app_majority(five_trees) assert tree_equal(got_majority, expected_majority) expected_strict = make_tree("(a,b,c,d,(e,f));") got_strict = app_strict(five_trees) assert tree_equal(got_strict, expected_strict) expected_0_3 = make_tree("((a,b),(((e,f),d),c))") got_0_3 = app_0_3(five_trees) assert tree_equal(got_0_3, expected_0_3) def test_piq_simulate_alignment(five_taxon_rooted_tree: PhyloNode) -> None: app = get_app("piq_simulate_alignment", model="JC") aln = app(five_taxon_rooted_tree) assert isinstance(aln, Alignment) assert sorted(aln.names) == sorted(five_taxon_rooted_tree.get_tip_names()) assert len(aln) == 1000 @pytest.mark.parametrize( ("app_name", "kwargs"), [ ("piq_build_tree", {"model": "JC"}), ( "piq_fit_tree", {"tree": make_tree(tip_names=["a", "b", "c"]), "model": "JC"}, ), ("piq_random_tree", {"tree_mode": piqtree.TreeGenMode.UNIFORM}), ("piq_jc_distances", {}), ("piq_nj_tree", {}), ("piq_model_finder", {}), ("piq_consensus_tree", {}), ("piq_simulate_alignment", {"model": "JC"}), ], ) def test_app_citation_bib(app_name: str, kwargs: dict) -> None: app = get_app(app_name, **kwargs) bib = app.bib assert "@article{piqtree," in bib assert "McArthur" in bib def test_quick_tree_hook(four_otu: Alignment) -> None: tree = four_otu.quick_tree(use_hook="piqtree") assert tree.params["provenance"] == "piqtree" iqtree-piqtree-b8a3d6a/tests/test_app/test_pickle.py000066400000000000000000000007031521173175100230100ustar00rootroot00000000000000"""Apps must be pickleable to be able to be run with parallel=True""" import pickle from cogent3 import get_app, make_tree from piqtree._app import _ALL_APP_NAMES def test_pickle() -> None: app_args = { "piq_build_tree": ("JC",), "piq_fit_tree": (make_tree("(a,b,(c,d));"), "JC"), } for app_name in _ALL_APP_NAMES: app = get_app(app_name, *app_args.get(app_name, ())) assert len(pickle.dumps(app)) > 0 iqtree-piqtree-b8a3d6a/tests/test_data.py000066400000000000000000000016431521173175100206370ustar00rootroot00000000000000import pathlib from pytest_mock import MockerFixture import piqtree def test_dataset_names() -> None: names = piqtree.dataset_names() assert len(names) > 0 def test_download_dataset(tmp_path: pathlib.Path, mocker: MockerFixture) -> None: # Mock the requests response fake_content = b"fake dataset data" mock_response = mocker.Mock() mock_response.iter_content.return_value = [fake_content] mocker.patch("piqtree._data.requests.get", return_value=mock_response) dataset_name = "example.tree.gz" dest_path = piqtree.download_dataset(dataset_name, dest_dir=tmp_path) assert dest_path.exists() assert dest_path.read_bytes() == fake_content # Check correct arguments expected_url = piqtree._data._get_url(dataset_name) piqtree._data.requests.get.assert_called_once_with( # type: ignore[attr-defined] expected_url, stream=True, timeout=20, ) iqtree-piqtree-b8a3d6a/tests/test_iqtree/000077500000000000000000000000001521173175100206415ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_build_tree.py000066400000000000000000000124141521173175100243720ustar00rootroot00000000000000import re import pytest from cogent3 import make_tree from cogent3.core.alignment import Alignment import piqtree from piqtree import make_model from piqtree.exceptions import IqTreeError from piqtree.model import ( CustomBaseFreq, DiscreteGammaModel, FreeRateModel, FreqType, LieModel, LieModelInstance, Model, RateModel, StandardDnaModel, SubstitutionModel, ) def check_build_tree_model( aln: Alignment, model: Model, *, coerce_str: bool = False, ) -> None: expected = make_tree("(Human,Chimpanzee,(SpermWhale,HumpbackW));") got = piqtree.build_tree(aln, str(model) if coerce_str else model) # Check topology assert expected.same_topology(got.unrooted()) # Check if branch lengths exist assert all(v.length is not None for v in got.get_edge_vector(include_root=False)) assert got.params["model"] == str(model) def check_build_tree( aln: Alignment, dna_model: SubstitutionModel, freq_type: FreqType | CustomBaseFreq | None = None, rate_model: RateModel | None = None, *, invariable_sites: bool = False, coerce_str: bool = False, ) -> None: model = Model( dna_model, freq_type=freq_type or None, invariable_sites=invariable_sites, rate_model=rate_model, ) check_build_tree_model(aln, model, coerce_str=coerce_str) @pytest.mark.parametrize("dna_model", StandardDnaModel.iter_available_models()) @pytest.mark.parametrize("freq_type", list(FreqType)) def test_non_lie_build_tree( four_otu: Alignment, dna_model: StandardDnaModel, freq_type: FreqType, ) -> None: check_build_tree(four_otu, dna_model, freq_type) @pytest.mark.parametrize("lie_model", LieModel.iter_available_models()) def test_lie_build_tree(four_otu: Alignment, lie_model: LieModelInstance) -> None: check_build_tree(four_otu, lie_model) @pytest.mark.parametrize("lie_model", LieModel.iter_available_models()[:3]) def test_str_build_tree(four_otu: Alignment, lie_model: LieModelInstance) -> None: check_build_tree(four_otu, lie_model, coerce_str=True) @pytest.mark.parametrize("dna_model", StandardDnaModel.iter_available_models()[:3]) @pytest.mark.parametrize("invariable_sites", [False, True]) @pytest.mark.parametrize( "rate_model", [ None, DiscreteGammaModel(), FreeRateModel(), DiscreteGammaModel(6), FreeRateModel(6), ], ) def test_rate_model_build_tree( four_otu: Alignment, dna_model: StandardDnaModel, invariable_sites: bool, rate_model: RateModel, ) -> None: check_build_tree( four_otu, dna_model, rate_model=rate_model, invariable_sites=invariable_sites, ) def test_build_tree_inadequate_bootstrapping(four_otu: Alignment) -> None: with pytest.raises(IqTreeError, match=re.escape("#replicates must be >= 1000")): piqtree.build_tree( four_otu, Model(StandardDnaModel.GTR), bootstrap_replicates=10, ) def test_build_tree_bootstrapping(four_otu: Alignment) -> None: tree = piqtree.build_tree( four_otu, Model(StandardDnaModel.GTR), bootstrap_replicates=1000, ) supported_node = max(tree.children, key=lambda x: len(x.children)) assert supported_node.support is not None @pytest.mark.parametrize( "model_str", [ "GTR{4.39,5.30,4.39,1.0,12.1}+F{0.1,0.2,0.3,0.4}+I{0.2}+G3{0.7}", "GTR{4.39,5.30,4.39,1.0,12.1,3.2}+R3{0.1,0.8,0.2,0.5,0.7,0.6}", "WS3.3b{0.5,-0.2}+F{0.6,0.1,0.2,0.1}+I{0.1}", ], ) def test_build_tree_paramaterisation(four_otu: Alignment, model_str: str) -> None: model = make_model(model_str) check_build_tree_model(four_otu, model) def test_invalid_protein_base_freq(four_otu: Alignment) -> None: base_freqs = ["0.05"] * 20 model = f"K81+F{{{','.join(base_freqs)}}}" with pytest.raises(IqTreeError): _ = piqtree.build_tree(four_otu, model) def test_too_many_dna_params(four_otu: Alignment) -> None: with pytest.raises(IqTreeError): _ = piqtree.build_tree(four_otu, "GTR{4.39,5.30,4.39,1.0,12.1,3.2,1.5}") def test_too_few_dna_params(four_otu: Alignment) -> None: with pytest.raises(IqTreeError): _ = piqtree.build_tree(four_otu, "GTR{4.39,5.30,4.39,1.0}") def test_build_tree_other_options(four_otu: Alignment) -> None: _ = piqtree.build_tree(four_otu, "GTR", other_options="--epsilon 0.1 -n 0") with pytest.raises(IqTreeError): # Invalid extra options _ = piqtree.build_tree(four_otu, "GTR", other_options="--epslon 0.1 -n 0") def test_build_tree_overridden_option(four_otu: Alignment) -> None: with pytest.raises( ValueError, match=re.escape( "Option '-seed' will be overridden by parameter of function. Use the parameter directly instead.", ), ): _ = piqtree.build_tree( four_otu, "GTR", other_options="--epsilon 0.1 -seed 123 -n 0", ) with pytest.raises( ValueError, match=re.escape( "Option '-bb' will be overridden by parameter of function. Use the parameter directly instead.", ), ): _ = piqtree.build_tree( four_otu, "GTR", other_options="--epsilon 0.1 -n 0 -bb 2000", ) iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_consensus_tree.py000066400000000000000000000131621521173175100253140ustar00rootroot00000000000000import re from collections.abc import Iterable import pytest from cogent3 import PhyloNode, make_tree from piqtree import consensus_tree from piqtree.exceptions import IqTreeError def tree_equal(tree1: PhyloNode, tree2: PhyloNode) -> bool: return str(tree1.sorted()) == str(tree2.sorted()) def test_majority_consensus_tree(five_trees: list[PhyloNode]) -> None: expected = make_tree("((a,b),(((e,f),d),c))") got_default = consensus_tree(five_trees) assert tree_equal(got_default, expected) got = consensus_tree(five_trees, min_support=0.5) assert tree_equal(got, expected) def test_higher_support(five_trees: list[PhyloNode]) -> None: expected_0_7 = make_tree("(a,b,c,(d,(e,f)));") got_0_7 = consensus_tree(five_trees, min_support=0.7) assert tree_equal(got_0_7, expected_0_7) expected_0_9 = make_tree("(a,b,c,d,(e,f));") got_0_9 = consensus_tree(five_trees, min_support=0.9) assert tree_equal(got_0_9, expected_0_9) def test_strict_consensus_tree(five_trees: list[PhyloNode]) -> None: expected = make_tree("(a,b,c,d,(e,f));") got = consensus_tree(five_trees, min_support=1) assert tree_equal(got, expected) def test_extended_majority_rule() -> None: tree1 = make_tree("(a,(b,(c,(d,e))))") tree2 = make_tree("(a,((b,c),(d,e)))") tree3 = make_tree("(a,((b,c),(d,e)))") tree4 = make_tree("(a,(c,(b,(d,e))))") tree5 = make_tree("(c,(b,(a,(d,e))))") got = consensus_tree([tree1, tree2, tree3, tree4, tree5], min_support=0) expected = make_tree("(a,((b,c),(d,e)))") assert tree_equal(got, expected) def test_lower_support(five_trees: list[PhyloNode]) -> None: expected = make_tree("((a,b),(((e,f),d),c))") for support in 0.1, 0.3: got = consensus_tree(five_trees, min_support=support) assert tree_equal(got, expected) def test_single_tree(five_trees: list[PhyloNode]) -> None: single_tree = five_trees[0] got = consensus_tree([single_tree]) assert tree_equal(got, single_tree) def test_even_majority_rule() -> None: tree1 = make_tree("(a,(b,(c,d)))") tree2 = make_tree("(a,(b,(c,d)))") tree3 = make_tree("(b,(a,(c,d)))") tree4 = make_tree("(c,(a,(b,d)))") expected = make_tree("(a,b,(c,d))") # Not including (b, (c,d)) as that's only in 2 got = consensus_tree([tree1, tree2, tree3, tree4]) assert tree_equal(got, expected) @pytest.mark.parametrize("min_support", [-1, -0.1, 1.00001, 2.5]) def test_bad_min_support(five_trees: list[PhyloNode], min_support: float) -> None: with pytest.raises( ValueError, match=re.escape( f"Only min support values in the range 0 <= value <= 1 are supported, got {min_support}", ), ): consensus_tree(five_trees, min_support=min_support) @pytest.mark.parametrize( "trees", [ [make_tree("(a,(b,(c,d)))"), make_tree("(a,(b,(c,(d,e))))")], [make_tree("(a,(b,(c,(d,e))))"), make_tree("(a,(b,(c,d)))")], (make_tree("(a,(b,(c,e)))"), make_tree("(a,(b,(c,d)))")), (make_tree("(a,(b,(c,d)))"), make_tree("(a,(b,(c,a)))")), ], ) def test_bad_trees(trees: Iterable[PhyloNode]) -> None: with pytest.raises(ValueError, match=re.escape("Trees must be on same taxa set.")): consensus_tree(trees) def test_no_trees() -> None: with pytest.raises(IqTreeError): consensus_tree([]) def _internal_supports(tree: PhyloNode) -> dict[frozenset, float]: return { frozenset(node.get_tip_names()): node.support for node in tree.postorder() if not node.is_tip() and not node.is_root() } @pytest.mark.parametrize( ("aggregate", "expected_ab", "expected_de"), [ ("mean", 93.0, 79.0), ("max", 95.0, 88.0), ("min", 91.0, 70.0), ], ) def test_support_aggregate( aggregate: str, expected_ab: float, expected_de: float, ) -> None: # inputs are rooted differently to the consensus, so matching is by bipartition tree1 = make_tree("(((a:1,b:1)95:1,c:1)88:1,d:1,e:1);") tree2 = make_tree("(((a:1,b:1)91:1,c:1)70:1,d:1,e:1);") got = consensus_tree([tree1, tree2], support_aggregate=aggregate) supports = _internal_supports(got) assert supports[frozenset({"c", "d", "e"})] == expected_ab # {a,b}|{c,d,e} assert supports[frozenset({"d", "e"})] == expected_de # {a,b,c}|{d,e} def test_support_aggregate_default_is_mean() -> None: tree1 = make_tree("(((a:1,b:1)95:1,c:1)88:1,d:1,e:1);") tree2 = make_tree("(((a:1,b:1)91:1,c:1)70:1,d:1,e:1);") supports = _internal_supports(consensus_tree([tree1, tree2])) assert supports[frozenset({"c", "d", "e"})] == 93.0 assert supports[frozenset({"d", "e"})] == 79.0 def test_support_aggregate_none_keeps_clade_frequency() -> None: tree1 = make_tree("(((a:1,b:1)95:1,c:1)88:1,d:1,e:1);") tree2 = make_tree("(((a:1,b:1)91:1,c:1)70:1,d:1,e:1);") got = consensus_tree([tree1, tree2], support_aggregate=None) assert set(_internal_supports(got).values()) == {100.0} def test_support_aggregate_clade_absent_from_inputs() -> None: # inputs have no support, so consensus keeps its clade-frequency value tree1 = make_tree("(((a,b),c),d,e);") tree2 = make_tree("(((a,b),c),d,e);") got = consensus_tree([tree1, tree2], support_aggregate="mean") assert set(_internal_supports(got).values()) == {100.0} @pytest.mark.parametrize("aggregate", ["median", "average", "MEAN", ""]) def test_bad_support_aggregate( five_trees: list[PhyloNode], aggregate: str, ) -> None: with pytest.raises( ValueError, match=re.escape("support_aggregate must be one of"), ): consensus_tree(five_trees, support_aggregate=aggregate) iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_distance.py000066400000000000000000000015561521173175100240530ustar00rootroot00000000000000from cogent3.core.alignment import Alignment from piqtree import jc_distances def test_jc_distance(five_otu: Alignment) -> None: dists = jc_distances(five_otu) assert ( 0 < dists["Human", "Chimpanzee"] < dists["Human", "Dugong"] ) # chimpanzee closer than rhesus assert ( 0 < dists["Human", "Rhesus"] < dists["Human", "Manatee"] ) # rhesus closer than manatee assert ( 0 < dists["Human", "Rhesus"] < dists["Human", "Dugong"] ) # rhesus closer than dugong assert ( 0 < dists["Chimpanzee", "Rhesus"] < dists["Chimpanzee", "Manatee"] ) # rhesus closer than manatee assert ( 0 < dists["Chimpanzee", "Rhesus"] < dists["Chimpanzee", "Dugong"] ) # rhesus closer than dugong assert ( 0 < dists["Manatee", "Dugong"] < dists["Manatee", "Rhesus"] ) # dugong closer than rhesus iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_fit_tree.py000066400000000000000000000171731521173175100240640ustar00rootroot00000000000000import re from typing import cast import numpy as np import pytest from cogent3 import get_app, make_tree from cogent3.app.result import model_result from cogent3.core.alignment import Alignment from cogent3.core.tree import PhyloNode import piqtree from piqtree.exceptions import IqTreeError from piqtree.model import Model, StandardDnaModel def check_model_name(got: PhyloNode, expected: str) -> None: got_model = cast("str", got.params.get("model")) assert got_model == expected def check_likelihood(got: PhyloNode, expected: model_result) -> None: assert got.params["lnL"] == pytest.approx(expected.lnL) def check_motif_probs(got: PhyloNode, expected: PhyloNode) -> None: expected_mprobs = expected.params["mprobs"] got_mprobs = got.params["mprobs"] expected_keys = set(expected_mprobs.keys()) got_keys = set(got_mprobs.keys()) # Check that the base characters are the same assert expected_keys == got_keys # Check that the probs are the same expected_values = [expected_mprobs[key] for key in expected_keys] got_values = [got_mprobs[key] for key in expected_keys] assert all( got == pytest.approx(exp) for got, exp in zip(got_values, expected_values, strict=True) ) def check_rate_parameters(got: PhyloNode, expected: PhyloNode) -> None: # Collect all rate parameters in got and expected exclude = {"length", "ENS", "paralinear", "mprobs"} expected_keys = { k for k in expected.get_edge_vector()[0].params if k not in exclude } got_keys = {k for k in got.get_edge_vector()[0].params if k not in exclude} # Check that the keys of rate are the same assert expected_keys == got_keys # Check that the values of rate are the same expected_values = [expected[0].params[key] for key in expected_keys] got_values = [got[0].params[key] for key in expected_keys] assert all( got == pytest.approx(exp, rel=1e-2) for got, exp in zip(got_values, expected_values, strict=True) ) def check_branch_lengths(got: PhyloNode, expected: PhyloNode) -> None: got_dists = got.tip_to_tip_distances() expected_dists = expected.tip_to_tip_distances() # make sure the distance matrices have the same name order # so we can just compare entire numpy arrays expected_dists = expected_dists.take_dists(got_dists.names) # Check that the keys of branch lengths are the same assert set(got_dists.names) == set(expected_dists.names) # Check that the branch lengths are the same np.testing.assert_allclose(got_dists.array, expected_dists.array, atol=1e-4) @pytest.mark.parametrize( ("iq_model", "c3_model"), [ (StandardDnaModel.JC, "JC69"), (StandardDnaModel.K80, "K80"), (StandardDnaModel.GTR, "GTR"), (StandardDnaModel.TN, "TN93"), (StandardDnaModel.HKY, "HKY85"), (StandardDnaModel.F81, "F81"), ], ) def test_fit_tree( three_otu: Alignment, iq_model: StandardDnaModel, c3_model: str, ) -> None: tree_topology = make_tree(tip_names=three_otu.names) app = get_app("model", c3_model, tree=tree_topology) expected = app(three_otu) model = Model(iq_model) got = piqtree.fit_tree(three_otu, tree_topology, model) check_likelihood(got, expected) check_motif_probs(got, expected.tree) check_rate_parameters(got, expected.tree) check_branch_lengths(got, expected.tree) check_model_name(got, str(model)) @pytest.mark.parametrize( ("iq_model", "c3_model"), [ (StandardDnaModel.JC, "JC69"), (StandardDnaModel.K80, "K80"), (StandardDnaModel.GTR, "GTR"), (StandardDnaModel.TN, "TN93"), (StandardDnaModel.HKY, "HKY85"), (StandardDnaModel.F81, "F81"), ], ) def test_fit_tree_str_model( three_otu: Alignment, iq_model: StandardDnaModel, c3_model: str, ) -> None: tree_topology = make_tree(tip_names=three_otu.names) app = get_app("model", c3_model, tree=tree_topology) expected = app(three_otu) model = str(Model(iq_model)) got = piqtree.fit_tree(three_otu, tree_topology, model) check_likelihood(got, expected) check_motif_probs(got, expected.tree) check_rate_parameters(got, expected.tree) check_branch_lengths(got, expected.tree) def test_fit_tree_fixed_branch_length( three_otu: Alignment, ) -> None: tree_topology: PhyloNode = make_tree(tip_names=three_otu.names) lengths = (0.1, 0.2, 0.3) for i, node in enumerate(tree_topology.postorder(include_self=False)): node.length = lengths[i] with_fixed = piqtree.fit_tree( three_otu, tree_topology, "GTR", bl_fixed=True, ) without_fixed = piqtree.fit_tree( three_otu, tree_topology, "GTR", bl_fixed=False, ) assert "lnL" in with_fixed.params assert "lnL" in without_fixed.params assert with_fixed.params["lnL"] != pytest.approx(without_fixed.params["lnL"]) for fixed_node, not_fixed_node, original_node in zip( with_fixed.postorder(include_self=False), without_fixed.postorder(include_self=False), tree_topology.postorder(include_self=False), strict=True, ): assert fixed_node.name == not_fixed_node.name assert not_fixed_node.name == original_node.name assert fixed_node.length == original_node.length assert not_fixed_node.length != original_node.length @pytest.mark.parametrize( "model_str", [ "GTR{4.39,5.30,4.39,1.0,12.1}+F{0.1,0.2,0.3,0.4}+I{0.2}+G3{0.7}", "GTR{4.39,5.30,4.39,1.0,12.1,3.2}+R3{0.1,0.8,0.2,0.5,0.7,0.6}", "WS3.3b{0.5,-0.2}+F{0.6,0.1,0.2,0.1}+I{0.1}", ], ) def test_fit_tree_paramaterisation(three_otu: Alignment, model_str: str) -> None: tree_topology = make_tree(tip_names=three_otu.names) tree = piqtree.fit_tree(three_otu, tree_topology, model_str) assert isinstance(tree.params["lnL"], float) for node in tree.preorder(include_self=False): assert cast("float", node.length) > 0 def test_special_characters(three_otu: Alignment) -> None: def _renamer(before: str) -> str: if before == three_otu.names[0]: return r"_F''<.'_l_?|\y}_F_o_!@#$%^&*x_''" return before three_otu = three_otu.renamed_seqs(_renamer) to_fit = make_tree(r"(_F''<.'_l_?|\y}_F_o_!@#$%^&*x_'', (Rhesus, Mouse))") tree = piqtree.fit_tree(three_otu, to_fit, "GTR") assert isinstance(tree.params["lnL"], float) for node in tree.preorder(include_self=False): assert cast("float", node.length) > 0 assert set(three_otu.names) == set(tree.get_tip_names()) def test_fit_tree_other_options(four_otu: Alignment) -> None: tree = make_tree(tip_names=four_otu.names) fitted_tree = piqtree.fit_tree( four_otu, tree, "GTR", other_options="-blmin 0.1 -blmax 0.5", ) for node in fitted_tree.postorder(include_self=False): assert node.length is not None assert 0.1 <= node.length <= 0.5 with pytest.raises(IqTreeError): # Invalid extra options fitted_tree = piqtree.fit_tree( four_otu, tree, "GTR", other_options="-blminn 0.1 -blmaax 0.5", ) def test_fit_tree_overridden_option(four_otu: Alignment) -> None: tree = make_tree(tip_names=four_otu.names) with pytest.raises( ValueError, match=re.escape( "Option '-blfix' will be overridden by parameter of function. Use the parameter directly instead.", ), ): # Invalid extra options _ = piqtree.fit_tree( four_otu, tree, "JC", other_options="-blfix", ) iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_model_finder.py000066400000000000000000000062301521173175100247020ustar00rootroot00000000000000import multiprocessing import re import pytest from cogent3.core.alignment import Alignment from piqtree.exceptions import IqTreeError from piqtree.iqtree import ModelFinderResult, ModelResultValue, model_finder def test_model_result_value_from_string() -> None: val = "123.45 10 0.678" result = ModelResultValue.from_string(val) assert result.lnL == 123.45 assert result.nfp == 10 assert result.tree_length == 0.678 @pytest.mark.parametrize( "bad_val", [ "123.45.00 10 0.678", # invalid float "123.45 10", # too few values ], ) def test_model_result_value_from_bad_string(bad_val: str) -> None: with pytest.raises(ValueError, match="Error parsing string"): _ = ModelResultValue.from_string(bad_val) @pytest.mark.parametrize("model", ["GTR+F", "GTR+F+G"]) def test_model_finder_result(model: str) -> None: raw_data = { model: "123.45 10 0.678", "best_model_AIC": model, "best_model_AICc": model, "best_model_BIC": model, "best_tree_AIC": "((a,b),(c,d));", # ignored "initTree": "((a,b),(c,d));", # ignored "partition_type": 0, # ignored } result = ModelFinderResult("test", raw_data) assert isinstance(result.model_stats[model], ModelResultValue) assert result.model_stats[model].lnL == 123.45 assert result.model_stats[model].nfp == 10 assert result.model_stats[model].tree_length == 0.678 def test_model_finder(five_otu: Alignment) -> None: result1 = model_finder(five_otu, rand_seed=1) result2 = model_finder( five_otu, num_threads=multiprocessing.cpu_count(), rand_seed=1, ) assert str(result1.best_aic) == str(result2.best_aic) assert str(result1.best_aicc) == str(result2.best_aicc) assert str(result1.best_bic) == str(result2.best_bic) def test_model_finder_restricted_submod(five_otu: Alignment) -> None: result = model_finder(five_otu, rand_seed=1, model_set={"HKY", "TIM"}) assert str(result.best_aic).startswith(("HKY", "TIM")) assert str(result.best_aicc).startswith(("HKY", "TIM")) assert str(result.best_bic).startswith(("HKY", "TIM")) def test_model_finder_other_options(five_otu: Alignment) -> None: result = model_finder( five_otu, rand_seed=1, model_set={"HKY", "TIM"}, other_options="-mtree", ) assert str(result.best_aic).startswith(("HKY", "TIM")) assert str(result.best_aicc).startswith(("HKY", "TIM")) assert str(result.best_bic).startswith(("HKY", "TIM")) with pytest.raises(IqTreeError): # Invalid extra options _ = model_finder( five_otu, rand_seed=1, model_set={"HKY", "TIM"}, other_options="-mtre", ) def test_model_finder_overridden_option(five_otu: Alignment) -> None: with pytest.raises( ValueError, match=re.escape( "Option '-mset' will be overridden by parameter of function. Use the parameter directly instead.", ), ): _ = model_finder( five_otu, rand_seed=1, model_set={"HKY", "TIM"}, other_options="-mset JC,HKY,TIM", ) iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_nj_tree.py000066400000000000000000000024611521173175100237030ustar00rootroot00000000000000import re from typing import cast import numpy as np import pytest from cogent3 import make_tree from cogent3.core.alignment import Alignment from piqtree import jc_distances, nj_tree def test_nj_tree(five_otu: Alignment) -> None: expected = make_tree("(((Human, Chimpanzee), Rhesus), Manatee, Dugong);") dists = jc_distances(five_otu) actual = nj_tree(dists) assert expected.same_topology(actual) def test_nj_tree_allow_negative(all_otu: Alignment) -> None: # a distance matrix can produce trees with negative branch lengths dists = jc_distances(all_otu) # check that all branch lengths are non-negative, by default tree1 = nj_tree(dists) assert all( cast("float", node.length) >= 0 for node in tree1.preorder(include_self=False) ) # check that some branch lengths are negative when allow_negative=True tree2 = nj_tree(dists, allow_negative=True) assert any( cast("float", node.length) < 0 for node in tree2.preorder(include_self=False) ) def test_nj_tree_nan(four_otu: Alignment) -> None: dists = jc_distances(four_otu) dists[1, 0] = dists[0, 1] = np.nan with pytest.raises( ValueError, match=re.escape("The pairwise distance matrix cannot contain NaN values."), ): nj_tree(dists, allow_negative=True) iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_protein_build_tree.py000066400000000000000000000032071521173175100261320ustar00rootroot00000000000000import pytest from cogent3.core.alignment import Alignment import piqtree from piqtree import make_model from piqtree.exceptions import IqTreeError from piqtree.model import ( AaModel, Model, SubstitutionModel, ) def check_build_tree_model( aln: Alignment, model: Model, *, coerce_str: bool = False, ) -> None: got = piqtree.build_tree(aln, str(model) if coerce_str else model, rand_seed=1) # Check if all branch lengths exist assert all(v.length is not None for v in got.get_edge_vector(include_root=False)) def check_build_tree( aln: Alignment, aa_model: SubstitutionModel, *, coerce_str: bool = False, ) -> None: model = Model(aa_model) check_build_tree_model(aln, model, coerce_str=coerce_str) @pytest.mark.parametrize("aa_model", AaModel.iter_available_models()) def test_protein_build_tree(protein_four_otu: Alignment, aa_model: AaModel) -> None: check_build_tree(protein_four_otu, aa_model, coerce_str=True) @pytest.mark.parametrize("aa_model", AaModel.iter_available_models()) def test_str_protein_build_tree(protein_four_otu: Alignment, aa_model: AaModel) -> None: check_build_tree(protein_four_otu, aa_model, coerce_str=False) def test_parameterised_model(protein_four_otu: Alignment) -> None: base_freq_values = ["0.05"] * 20 model = make_model(f"rtREV+F{{{','.join(base_freq_values)}}}+I{{0.2}}+G3{{1.2}}") check_build_tree_model(protein_four_otu, model) def test_invalid_protein_base_freq(protein_four_otu: Alignment) -> None: model = "FLAVI+F{0.2,0.3,0.4,0.1}" with pytest.raises(IqTreeError): _ = piqtree.build_tree(protein_four_otu, model) iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_random_tree.py000066400000000000000000000026311521173175100245530ustar00rootroot00000000000000import pytest from piqtree import TreeGenMode, random_tree from piqtree.exceptions import IqTreeError @pytest.mark.parametrize("num_taxa", [10, 50, 100]) @pytest.mark.parametrize("tree_mode", list(TreeGenMode)) def test_random_tree(num_taxa: int, tree_mode: TreeGenMode) -> None: tree = random_tree(num_taxa, tree_mode, rand_seed=1) assert len(tree.tips()) == num_taxa @pytest.mark.parametrize("rand_seed", [0, 1234]) def test_random_tree_determinism(rand_seed: int) -> None: tree_1 = random_tree(10, TreeGenMode.YULE_HARDING, rand_seed=rand_seed) tree_2 = random_tree(10, TreeGenMode.YULE_HARDING, rand_seed=rand_seed) for node_a, node_b in zip(tree_1.postorder(), tree_2.postorder(), strict=True): assert node_a.name == node_b.name assert node_a.length == node_b.length assert len(node_a.children) == len(node_b.children) @pytest.mark.parametrize("num_taxa", [10, 50, 100]) @pytest.mark.parametrize("tree_mode", list(TreeGenMode)) def test_random_tree_no_seed(num_taxa: int, tree_mode: TreeGenMode) -> None: tree = random_tree(num_taxa, tree_mode) assert len(tree.tips()) == num_taxa @pytest.mark.parametrize("num_taxa", [-1, 0, 1, 2]) @pytest.mark.parametrize("tree_mode", list(TreeGenMode)) def test_invalid_taxa( num_taxa: int, tree_mode: TreeGenMode, ) -> None: with pytest.raises(IqTreeError): _ = random_tree(num_taxa, tree_mode, rand_seed=1) iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_robinson_foulds.py000066400000000000000000000005501521173175100254570ustar00rootroot00000000000000import numpy as np from cogent3 import make_tree from numpy.testing import assert_array_equal import piqtree def test_robinson_foulds() -> None: tree1 = make_tree("(A,B,(C,D));") tree2 = make_tree("(A,C,(B,D));") pairwise_distances = piqtree.robinson_foulds([tree1, tree2]) assert_array_equal(pairwise_distances, np.array([[0, 2], [2, 0]])) iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_segmentation_fault.py000066400000000000000000000043041521173175100261430ustar00rootroot00000000000000"""Test combinations of calls which under previous versions resulted in a segmentation fault.""" import pytest from cogent3 import make_aligned_seqs, make_tree from cogent3.core.alignment import Alignment from piqtree import TreeGenMode, build_tree, fit_tree, random_tree from piqtree.exceptions import IqTreeError from piqtree.model import DiscreteGammaModel, FreeRateModel, Model, StandardDnaModel @pytest.fixture def tiny_alignment() -> Alignment: return make_aligned_seqs( {"a": "GGG", "b": "GGC", "c": "AAC", "d": "AAA"}, moltype="dna", ) def test_two_build_random_tree(tiny_alignment: Alignment) -> None: """ Calling build tree twice followed by random tree with a bad input used to result in a Segmentation Fault in a previous version. """ build_tree(tiny_alignment, Model(StandardDnaModel.JC), 1) build_tree(tiny_alignment, Model(StandardDnaModel.JC), 2) with pytest.raises(IqTreeError): random_tree(2, TreeGenMode.BALANCED, 1) def test_two_fit_random_tree(tiny_alignment: Alignment) -> None: """ Calling fit tree twice followed by random tree with a bad input used to result in a Segmentation Fault in a previous version. """ tree = make_tree("(a,b,(c,d));") fit_tree(tiny_alignment, tree, Model(StandardDnaModel.JC)) fit_tree(tiny_alignment, tree, Model(StandardDnaModel.JC)) with pytest.raises(IqTreeError): random_tree(2, TreeGenMode.BALANCED, 1) @pytest.mark.parametrize("rate_model_class", [DiscreteGammaModel, FreeRateModel]) @pytest.mark.parametrize("categories", [0, -4]) def test_two_invalid_models( tiny_alignment: Alignment, rate_model_class: type[DiscreteGammaModel] | type[FreeRateModel], categories: int, ) -> None: """ Calling build_tree multiple times with an invalid model has resulted in a Segmentation Fault. """ with pytest.raises(IqTreeError): _ = build_tree( tiny_alignment, Model(StandardDnaModel.JC, rate_model=rate_model_class(categories)), ) with pytest.raises(IqTreeError): _ = build_tree( tiny_alignment, Model(StandardDnaModel.JC, rate_model=rate_model_class(categories)), ) iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_simulate_alignment.py000066400000000000000000000127671521173175100261500ustar00rootroot00000000000000import re from typing import cast import pytest from cogent3 import make_tree from cogent3.core.alignment import Alignment from cogent3.core.tree import PhyloNode from piqtree import Model, simulate_alignment from piqtree.distribution import ( IndelDistribution, IndelGeometric, IndelLavalette, IndelNegativeBinomial, IndelZipfian, ) from piqtree.iqtree._alignment import UNSUPPORTED_MODELS from piqtree.model import ( AaModel, LieModel, StandardDnaModel, SubstitutionModel, ) def check_simulate_alignment( tree: PhyloNode, model: Model | str, length: int | None = None, insertion_rate: float = 0.0, deletion_rate: float = 0.0, insertion_size_distribution: IndelDistribution | str = "POW{1.7/100}", deletion_size_distribution: IndelDistribution | str = "POW{1.7/100}", seed: int | None = None, ) -> Alignment: if length is None: aln = simulate_alignment( tree, model, rand_seed=seed, insertion_rate=insertion_rate, deletion_rate=deletion_rate, insertion_size_distribution=insertion_size_distribution, deletion_size_distribution=deletion_size_distribution, ) else: aln = simulate_alignment( tree, model, length, rand_seed=seed, insertion_rate=insertion_rate, deletion_rate=deletion_rate, insertion_size_distribution=insertion_size_distribution, deletion_size_distribution=deletion_size_distribution, ) if length is None: length = 1000 if insertion_rate > 0: assert len(aln) >= length else: assert len(aln) == length assert aln.num_seqs == len(tree.tips()) assert sorted(aln.names) == sorted(tree.get_tip_names()) return aln @pytest.mark.parametrize( "model", [ *StandardDnaModel.iter_available_models(), *LieModel.iter_available_models(), *AaModel.iter_available_models(), ], ) def test_rooted_tree( five_taxon_rooted_tree: PhyloNode, model: SubstitutionModel, ) -> None: if model.base_model in UNSUPPORTED_MODELS: with pytest.raises( ValueError, match=re.escape( f"Lie Model {cast('LieModel', model.base_model).value} is unsupported.", ), ): check_simulate_alignment(five_taxon_rooted_tree, Model(model)) else: check_simulate_alignment(five_taxon_rooted_tree, Model(model)) @pytest.mark.parametrize( "model", [ *StandardDnaModel.iter_available_models(), *LieModel.iter_available_models(), *AaModel.iter_available_models(), ], ) def test_unrooted_tree( four_taxon_unrooted_tree: PhyloNode, model: SubstitutionModel, ) -> None: if model.base_model in UNSUPPORTED_MODELS: with pytest.raises( ValueError, match=re.escape( f"Lie Model {cast('LieModel', model.base_model).value} is unsupported.", ), ): check_simulate_alignment(four_taxon_unrooted_tree, Model(model)) else: check_simulate_alignment(four_taxon_unrooted_tree, Model(model)) @pytest.mark.parametrize("length", [None, 500, 1500]) def test_lengths( four_taxon_unrooted_tree: PhyloNode, length: int | None, ) -> None: check_simulate_alignment( four_taxon_unrooted_tree, Model(StandardDnaModel.GTR), length=length, ) @pytest.mark.parametrize("insertion_rate", [0.0, 0.03, 0.2]) @pytest.mark.parametrize("deletion_rate", [0.0, 0.04, 0.18]) def test_indel_rates( four_taxon_unrooted_tree: PhyloNode, insertion_rate: float, deletion_rate: float, ) -> None: check_simulate_alignment( four_taxon_unrooted_tree, Model(StandardDnaModel.GTR), insertion_rate=insertion_rate, deletion_rate=deletion_rate, ) @pytest.mark.parametrize( "indel_size_distributions", [ (IndelGeometric(5), IndelGeometric(4)), (IndelNegativeBinomial(5, 20), IndelZipfian(1.5, 10)), (IndelLavalette(1.5, 10), IndelLavalette(1.5, 10)), ], ) def test_indel_sizes( four_taxon_unrooted_tree: PhyloNode, indel_size_distributions: tuple[IndelDistribution | str, IndelDistribution | str], ) -> None: insertion_size_distribution = indel_size_distributions[0] deletion_size_distribution = indel_size_distributions[1] aln = check_simulate_alignment( four_taxon_unrooted_tree, "GTR{1.0,2.0,1.5,3.7,2.8}+F{0.1,0.2,0.3,0.4}", insertion_rate=0.1, deletion_rate=0.05, insertion_size_distribution=insertion_size_distribution, deletion_size_distribution=deletion_size_distribution, seed=1, ) aln_indel_str = check_simulate_alignment( four_taxon_unrooted_tree, "GTR{1.0,2.0,1.5,3.7,2.8}+F{0.1,0.2,0.3,0.4}", insertion_rate=0.1, deletion_rate=0.05, insertion_size_distribution=str(insertion_size_distribution), deletion_size_distribution=str(deletion_size_distribution), seed=1, ) assert aln.names == aln_indel_str.names for name in aln.names: assert aln.get_seq(name) == aln_indel_str.get_seq(name) def test_root_seq() -> None: tree = make_tree("((a:0.8,(b:1.2,c:0)):0.0,d:0.5,e:0.0)") root_seq = "GGGGCCCCAAAATTTT" * 10 aln = simulate_alignment(tree, "JC", len(root_seq), root_seq=root_seq) assert str(aln.get_seq("c")) == root_seq assert str(aln.get_seq("e")) == root_seq iqtree-piqtree-b8a3d6a/tests/test_iqtree/test_tree_yaml.py000066400000000000000000000252541521173175100242430ustar00rootroot00000000000000import re from typing import Any import pytest from cogent3 import make_tree from piqtree import make_model from piqtree.exceptions import ParseIqTreeError from piqtree.iqtree._tree import _process_tree_yaml, _tree_equal @pytest.fixture def newick_not_in_candidates() -> list[dict[str, Any]]: return [ { # Newick string not in candidate set (different branch length) "CandidateSet": { 0: "-6519.33018689 (0:0.0058955371,1:0.0026486308,(2:0.0230933557,3:0.3069062230):0.01387802789);", 1: "-6540.1924365 (0:0.0059276645,(1:0.0026255655,2:0.0369876991):2.43436209e-06,3:0.3205542282);", 2: "-6540.32542968 (0:0.0059468612,(1:0.0021841363,3:0.3203544844):2.076530752e-06,2:0.0369270512);", }, "ModelDNA": { "rates": "1, 3.815110072, 1, 1, 3.815110072, 1", "state_freq": "0.3640205807, 0.1862366777, 0.217291437, 0.2324513047", }, "PhyloTree": { "newick": "(0:0.0068955371,1:0.0026486308,(2:0.0230933557,3:0.3069062230):0.01387802789);", }, "StopRule": { "curIteration": 101, "start_real_time": 1731027583, "time_vec": None, }, "boot_consense_logl": 0, "contree_rfdist": -1, "finished": True, "finishedCandidateSet": True, "finishedModelFinal": True, "finishedModelInit": True, "initTree": "(0:0.0063001853,1:0.0022115739,(2:0.0203850510,3:0.3497395366):0.01883712169);", "iqtree": { "seed": 598834595, "start_time": 1731027582, "version": "2.3.6.lib", }, }, { # Newick string not in candidate set (different names) "CandidateSet": { 0: "-6519.33018689 (0:0.0058955371,2:0.0026486308,(1:0.0230933557,3:0.3069062230):0.01387802789);", 1: "-6540.1924365 (0:0.0059276645,(1:0.0026255655,2:0.0369876991):2.43436209e-06,3:0.3205542282);", 2: "-6540.32542968 (0:0.0059468612,(1:0.0021841363,3:0.3203544844):2.076530752e-06,2:0.0369270512);", }, "ModelDNA": { "rates": "1, 3.815110072, 1, 1, 3.815110072, 1", "state_freq": "0.3640205807, 0.1862366777, 0.217291437, 0.2324513047", }, "PhyloTree": { "newick": "(0:0.0058955371,1:0.0026486308,(2:0.0230933557,3:0.3069062230):0.01387802789);", }, "StopRule": { "curIteration": 101, "start_real_time": 1731027583, "time_vec": None, }, "boot_consense_logl": 0, "contree_rfdist": -1, "finished": True, "finishedCandidateSet": True, "finishedModelFinal": True, "finishedModelInit": True, "initTree": "(0:0.0063001853,1:0.0022115739,(2:0.0203850510,3:0.3497395366):0.01883712169);", "iqtree": { "seed": 598834595, "start_time": 1731027582, "version": "2.3.6.lib", }, }, ] @pytest.fixture def non_lie_dna_with_rate_model() -> dict[str, Any]: return { "CandidateSet": { 0: "-6736.94578464 (0:0.0063211201,1:0.0029675780,(2:0.0228519739,3:0.3072009029):0.01373649616);", 1: "-6757.78815651 (0:0.0063607954,(1:0.0030079874,2:0.0365597715):2.296825575e-06,3:0.3208135518);", 2: "-6758.07765021 (0:0.0063826033,(1:0.0021953253,3:0.3207201830):0.0001145372551,2:0.0365362763);", }, "ModelDNA": { "rates": "1, 3.82025079, 1, 1, 3.82025079, 1", "state_freq": "0.3628523161, 0.1852938562, 0.2173913044, 0.2344625233", }, "PhyloTree": { "newick": "(0:0.0063211201,1:0.0029675780,(2:0.0228519739,3:0.3072009029):0.01373649616);", }, "RateGammaInvar": {"gamma_shape": 1.698497993, "p_invar": 1.002841144e-06}, "StopRule": { "curIteration": 101, "start_real_time": 1724397157, "time_vec": None, }, "boot_consense_logl": 0, "contree_rfdist": -1, "finished": True, "finishedCandidateSet": True, "finishedModelFinal": True, "finishedModelInit": True, "initTree": "(0:0.0063680036,1:0.0026681490,(2:0.0183861083,3:0.3034074996):0.01838610827);", "iqtree": {"seed": 95633264, "start_time": 1724397157, "version": "2.3.6.lib"}, } @pytest.fixture def lie_dna_model() -> dict[str, Any]: return { "CandidateSet": { 0: "-6606.82337571 ((0:0.0058632731,(2:0.0225450645,3:0.3055011501):0.01414755595):2.340509431e-06,1:0.0026433577):0;", 1: "-6606.82337581 (0:0.0058609304,(1:0.0026456850,(2:0.0225450645,3:0.3055011501):0.01414755618):2.340509431e-06):0;", 2: "-6606.82337581 ((0:0.0058632731,1:0.0026456850):2.340509431e-06,(2:0.0225450645,3:0.3055011501):0.01414520892):0;", 3: "-6606.82337594 (((0:0.0058630055,1:0.0026461740):0.01414791335,2:0.0225451031):0.1178978025,3:0.1876035160):0;", 4: "-6628.65519886 (0:0.0000023102,((1:0.0027556399,3:0.3193110364):2.07651076e-06,2:0.0366286909):0.005770021808):1e-06;", 5: "-6628.70596445 (0:0.0000022647,((1:0.0027641463,2:0.0366284785):2.43434433e-06,3:0.3193357780):0.005401508376):1e-06;", }, "ModelLieMarkovRY2.2b": { "model_parameters": 0.4841804549, "state_freq": "0.25, 0.25, 0.25, 0.25", }, "PhyloTree": { "newick": "((0:0.0058632731,(2:0.0225450645,3:0.3055011501):0.01414755595):2.340509431e-06,1:0.0026433577):0;", }, "StopRule": { "curIteration": 101, "start_real_time": 1729226726, "time_vec": None, }, "boot_consense_logl": 0, "contree_rfdist": -1, "finished": True, "finishedCandidateSet": True, "finishedModelFinal": True, "finishedModelInit": True, "initTree": "(0:0.0063001853,1:0.0022115739,(2:0.0203850510,3:0.3497395366):0.01883712169);", "iqtree": {"seed": 1, "start_time": 1729226725, "version": "2.3.6.lib"}, } @pytest.fixture def unrest_model() -> dict[str, Any]: return { "CandidateSet": { 0: "-6736.94578464 (0:0.0063211201,1:0.0029675780,(2:0.0228519739,3:0.3072009029):0.01373649616);", 1: "-6757.78815651 (0:0.0063607954,(1:0.0030079874,2:0.0365597715):2.296825575e-06,3:0.3208135518);", 2: "-6758.07765021 (0:0.0063826033,(1:0.0021953253,3:0.3207201830):0.0001145372551,2:0.0365362763);", }, "ModelUnrest": { "rates": "0.9543854572, 2.942336813, 0.5526681694, 0.7599462192, 0.897052927, 3.38882313, 4.630689862, 0.7223043133, 0.4970030179, 0.8401385788, 2.854877074, 1", "state_freq": "0.3234606464, 0.2202693695, 0.2343932981, 0.221876686", }, "PhyloTree": { "newick": "(0:0.0063211201,1:0.0029675780,(2:0.0228519739,3:0.3072009029):0.01373649616);", }, } def test_newick_not_in_candidates( newick_not_in_candidates: list[dict[str, Any]], ) -> None: for yaml in newick_not_in_candidates: with pytest.raises( ParseIqTreeError, match=re.escape("IQ-TREE output is malformed, likelihood not found."), ): _ = _process_tree_yaml(yaml, ["a", "b", "c", "d"], make_model("JC")) def test_non_lie_dna_with_rate_model( non_lie_dna_with_rate_model: dict[str, Any], ) -> None: # test parsing yaml file containing fits from non-Lie DnaModel and rate heterogeneity model edge_params = { "rates": { "A/C": 1.0, "A/G": 3.82025079, "A/T": 1.0, "C/G": 1.0, "C/T": 3.82025079, }, "mprobs": { "A": 0.3628523161, "C": 0.1852938562, "G": 0.2173913044, "T": 0.2344625233, }, } rate_params = {"gamma_shape": 1.698497993, "p_invar": 1.002841144e-06} tree = _process_tree_yaml( non_lie_dna_with_rate_model, ["a", "b", "c", "d"], make_model("GTR+I+G"), ) for rate, value in edge_params["rates"].items(): assert tree[0].params[rate] == value assert tree.params["RateGammaInvar"] == rate_params def test_non_lie_dna_model_motif_absent( non_lie_dna_with_rate_model: dict[str, Any], ) -> None: non_lie_dna_with_rate_model["ModelDNA"].pop("state_freq") with pytest.raises( ParseIqTreeError, match=re.escape("IQ-TREE output is malformed, motif parameters not found."), ): _ = _process_tree_yaml( non_lie_dna_with_rate_model, ["a", "b", "c", "d"], make_model("GTR+I+G"), ) def test_non_lie_dna_model_rate_absent( non_lie_dna_with_rate_model: dict[str, Any], ) -> None: non_lie_dna_with_rate_model["ModelDNA"].pop("rates") with pytest.raises( ParseIqTreeError, match=re.escape("IQ-TREE output is malformed, rate parameters not found."), ): _ = _process_tree_yaml( non_lie_dna_with_rate_model, ["a", "b", "c", "d"], make_model("GTR+I+G"), ) def test_lie_dna_model( lie_dna_model: dict[str, Any], ) -> None: # test parsing yaml file containing fits from Lie DnaModel model_parameters = { "model_parameters": 0.4841804549, "mprobs": {"A": 0.25, "C": 0.25, "G": 0.25, "T": 0.25}, } tree = _process_tree_yaml(lie_dna_model, ["a", "b", "c", "d"], make_model("RY2.2b")) assert tree.params["ModelLieMarkovRY2.2b"] == model_parameters def test_lie_dna_model_motif_absent( lie_dna_model: dict[str, Any], ) -> None: lie_dna_model["ModelLieMarkovRY2.2b"].pop("state_freq") with pytest.raises( ParseIqTreeError, match=re.escape("IQ-TREE output is malformed, motif parameters not found."), ): _ = _process_tree_yaml( lie_dna_model, ["a", "b", "c", "d"], make_model("RY2.2b"), ) def test_unrest_model( unrest_model: dict[str, Any], ) -> None: tree = _process_tree_yaml(unrest_model, ["a", "b", "c", "d"], make_model("UNREST")) assert "A/C" in tree[0].params assert tree.params["mprobs"] @pytest.mark.parametrize( ("candidate", "expected"), [ ("((a:1.0,b:0.9),c:0.8);", True), ("((a:0.9,b:0.9),c:0.8);", False), ("((a:1.0,c:0.8),b:0.9);", False), ], ) def test_tree_equal(candidate: str, expected: bool) -> None: tree = make_tree("((a:1.0,b:0.9),c:0.8);") candidate_tree = make_tree(candidate) assert _tree_equal(tree, candidate_tree) == expected iqtree-piqtree-b8a3d6a/tests/test_model/000077500000000000000000000000001521173175100204505ustar00rootroot00000000000000iqtree-piqtree-b8a3d6a/tests/test_model/test_freq_type.py000066400000000000000000000062151521173175100240630ustar00rootroot00000000000000import re from collections.abc import Sequence import pytest from piqtree.model import CustomBaseFreq, FreqType, get_freq_type def test_number_of_descriptions() -> None: assert len(FreqType) == len(FreqType._descriptions()) def test_descriptions_exist() -> None: for freq_type in FreqType: # Raises an error if description not present _ = freq_type.description _ = get_freq_type("F{0.1,0.2,0.3,0.4}").description @pytest.mark.parametrize( ("freq_type", "iqtree_str"), [ (FreqType.F, "F"), (FreqType.FO, "FO"), (FreqType.FQ, "FQ"), ("F", "F"), ("FO", "FO"), ("FQ", "FQ"), ("+F", "F"), ("+FO", "FO"), ("+FQ", "FQ"), ], ) def test_get_freq_type(freq_type: FreqType | str, iqtree_str: str) -> None: out = get_freq_type(freq_type) assert isinstance(out, FreqType) assert out.iqtree_str() == iqtree_str @pytest.mark.parametrize( ("freq_type", "iqtree_str"), [ ("+F{0.1,0.2,0.3,0.4}", "F{0.1,0.2,0.3,0.4}"), ( f"+F{{{','.join(map(str, [0.05] * 20))}}}", f"F{{{','.join(map(str, [0.05] * 20))}}}", ), ], ) def test_get_custom_freq_type(freq_type: str, iqtree_str: str) -> None: out = get_freq_type(freq_type) assert isinstance(out, CustomBaseFreq) assert out.iqtree_str() == iqtree_str @pytest.mark.parametrize( "freq_type", ["F0", "+F0", "+G", "+R9"], ) def test_invalid_freq_type_name(freq_type: str) -> None: with pytest.raises( ValueError, match=re.escape(f"Unknown state frequency type: {freq_type!r}"), ): _ = get_freq_type(freq_type) @pytest.mark.parametrize( "freqs", [[0.1, 0.2, 0.7], [0.2] * 5, [0.04] * 25], ) def test_invalid_freq_type_params(freqs: Sequence[float]) -> None: with pytest.raises( ValueError, match=re.escape( f"Expected either 4 frequencies for DNA model or 20 for AA model but got {len(freqs)}", ), ): _ = get_freq_type(f"F{{{','.join(map(str, freqs))}}}") def test_custom_empty_str() -> None: with pytest.raises( ValueError, match=re.escape("An empty string does not specify base frequencies."), ): _ = CustomBaseFreq.from_str("") def test_custom_bad_start() -> None: base_freq_str = "G{0.1,0.2,0.3,0.4}" with pytest.raises( ValueError, match=re.escape( f"A CustomBaseFreq must start with F but got {base_freq_str!r}.", ), ): _ = CustomBaseFreq.from_str(base_freq_str) def test_custom_missing_bracket() -> None: base_freq_str = "F{0.1,0.2,0.3,0.4" with pytest.raises( ValueError, match=re.escape( f"A CustomBaseFreq must be parameterised with {{}} but got {base_freq_str!r}.", ), ): _ = CustomBaseFreq.from_str(base_freq_str) def test_custom_bad_parameter() -> None: base_freq_str = "F{0.1,0.2,0.3,cat}" with pytest.raises( ValueError, match=re.escape( f"Unable to parse parameters for CustomBaseFreq: {base_freq_str!r}.", ), ): _ = CustomBaseFreq.from_str(base_freq_str) iqtree-piqtree-b8a3d6a/tests/test_model/test_model.py000066400000000000000000000163411521173175100231660ustar00rootroot00000000000000import re import pytest from piqtree.model import ( AaModel, CustomBaseFreq, DiscreteGammaModel, FreeRateModel, FreqType, LieModel, Model, RateModel, StandardDnaModel, SubstitutionModel, make_model, ) def check_make_model( sub_mod: SubstitutionModel, freq_type: FreqType | CustomBaseFreq | None = None, rate_model: RateModel | None = None, *, invariable_sites: bool | float = False, ) -> None: model = Model(sub_mod, freq_type, rate_model, invariable_sites=invariable_sites) expected = str(model) # Check the expected string is approximately generated correctly # float and True should be True, False should be False assert (invariable_sites is not False) == model.invariable_sites if not isinstance(invariable_sites, bool): assert re.search(r"\+I\{\d+(\.\d+)?\}", expected) assert model.proportion_invariable_sites == invariable_sites assert model.invariable_sites else: assert model.proportion_invariable_sites is None assert model.invariable_sites == invariable_sites assert ("+I" in expected) == invariable_sites if isinstance(rate_model, DiscreteGammaModel): assert isinstance(model.rate_model, DiscreteGammaModel) assert "+G" in expected if rate_model.alpha is not None: assert re.search(r"\+G\d*\{\d+(\.\d+)?\}", expected) else: assert not isinstance(model.rate_model, DiscreteGammaModel) assert "+G" not in expected if isinstance(rate_model, FreeRateModel): assert isinstance(model.rate_model, FreeRateModel) assert "+R" in expected if rate_model.rates is not None: assert re.search(r"\+R\d*\{\d+(\.\d+)?(,\d+(\.\d+)?)*\}", expected) else: assert not isinstance(model.rate_model, FreeRateModel) assert "+R" not in expected if freq_type is not None: assert "+F" in expected if isinstance(freq_type, CustomBaseFreq): assert re.search(r"\+F\{\d+(\.\d+)?(,\d+(\.\d+)?)*\}", expected) else: assert "+F" not in expected # Check make_model got = str(make_model(expected)) assert got == expected @pytest.mark.parametrize( "sub_mod", [ *StandardDnaModel.iter_available_models(), StandardDnaModel.GTR([4.39, 5.30, 4.39, 1.0, 12.1]), StandardDnaModel.TIM2([4.39, 5.30, 12.1]), *LieModel.iter_available_models(), *AaModel.iter_available_models(), ], ) def test_make_model_sub_mod(sub_mod: SubstitutionModel) -> None: check_make_model(sub_mod) @pytest.mark.parametrize( "sub_mod", [ StandardDnaModel.iter_available_models()[0], LieModel.iter_available_models()[0], AaModel.iter_available_models()[0], ], ) @pytest.mark.parametrize( "freq_type", [*list(FreqType), CustomBaseFreq([0.1, 0.2, 0.3, 0.4])], ) def test_make_model_freq_type( sub_mod: SubstitutionModel, freq_type: FreqType | CustomBaseFreq, ) -> None: check_make_model(sub_mod, freq_type=freq_type) @pytest.mark.parametrize( "sub_mod", [ StandardDnaModel.iter_available_models()[-1], LieModel.iter_available_models()[-1], AaModel.iter_available_models()[-1], ], ) @pytest.mark.parametrize("invariable_sites", [0.2, True]) def test_make_model_invar_sites( sub_mod: SubstitutionModel, invariable_sites: bool | float, ) -> None: check_make_model(sub_mod, invariable_sites=invariable_sites) @pytest.mark.parametrize( "sub_mod", [ StandardDnaModel.iter_available_models()[1], LieModel.iter_available_models()[1], AaModel.iter_available_models()[1], ], ) @pytest.mark.parametrize( "rate_model", [ DiscreteGammaModel(), DiscreteGammaModel(6), DiscreteGammaModel(2, 0.3), FreeRateModel(), FreeRateModel(6), FreeRateModel(2, [0.4, 0.6], [0.9, 0.1]), ], ) def test_make_model_rate_model( sub_mod: SubstitutionModel, rate_model: RateModel, ) -> None: check_make_model(sub_mod, rate_model=rate_model) @pytest.mark.parametrize( "sub_mod", [ *StandardDnaModel.iter_available_models()[:3], StandardDnaModel.GTR([1.0, 2.0, 1.5, 3.7, 2.8]), *LieModel.iter_available_models()[:3], *AaModel.iter_available_models()[:3], ], ) @pytest.mark.parametrize( "freq_type", [None, FreqType.FQ, CustomBaseFreq([0.1, 0.2, 0.3, 0.4])], ) @pytest.mark.parametrize("invariable_sites", [False, 0.2, True]) @pytest.mark.parametrize( "rate_model", [ None, DiscreteGammaModel(6), DiscreteGammaModel(2, 0.3), FreeRateModel(), FreeRateModel(2, [0.4, 0.6], [0.9, 0.1]), ], ) def test_make_model( sub_mod: SubstitutionModel, freq_type: FreqType | CustomBaseFreq | None, invariable_sites: bool | float, rate_model: RateModel | None, ) -> None: check_make_model(sub_mod, freq_type, rate_model, invariable_sites=invariable_sites) def test_model_repr() -> None: model = make_model("GTR") assert repr(model) == "Model(submod_type=GTR, freq_type=None, rate_type=None)" model = make_model("MK6.6+FO+R3") assert repr(model) == "Model(submod_type=MK6.6, freq_type=FO, rate_type=R3)" model = make_model("12.12+G") assert repr(model) == "Model(submod_type=12.12, freq_type=None, rate_type=G)" model = make_model("NQ.mammal+FQ") assert repr(model) == "Model(submod_type=NQ.mammal, freq_type=FQ, rate_type=None)" def test_bad_sub_model() -> None: with pytest.raises( ValueError, match=re.escape("Unknown substitution model: 'GYR'"), ): make_model("GYR") def test_multiple_freq_type() -> None: with pytest.raises( ValueError, match=re.escape( "Model 'GTR+FO+FO' contains multiple base frequency specifications.", ), ): make_model("GTR+FO+FO") def test_multiple_invariable_sites() -> None: with pytest.raises( ValueError, match=re.escape( "Model 'GTR+I+I' contains multiple specifications for invariable sites.", ), ): make_model("GTR+I+I") def test_multiple_rate_het() -> None: with pytest.raises( ValueError, match=re.escape( "Model 'GTR+G+R' contains multiple rate heterogeneity specifications.", ), ): make_model("GTR+G+R") def test_unexpected_component() -> None: with pytest.raises( ValueError, match=re.escape( "Model 'GTR+Z' contains unexpected component.", ), ): make_model("GTR+Z") def test_missing_invar_brackets() -> None: with pytest.raises( ValueError, match=re.escape( "Invalid specification for proportion of invariable sites, got 'I{0.5'.", ), ): _ = make_model("GTR+I{0.5") with pytest.raises( ValueError, match=re.escape( "Invalid specification for proportion of invariable sites, got 'I0.3}'.", ), ): _ = make_model("GTR+I0.3}") def test_invar_invalid_proportion() -> None: with pytest.raises( ValueError, match=re.escape("Failed to read proportion of invariable sites, got 'I{cat}'"), ): _ = make_model("HKY+I{cat}") iqtree-piqtree-b8a3d6a/tests/test_model/test_options.py000066400000000000000000000040411521173175100235530ustar00rootroot00000000000000# testing the display of functions from typing import Literal import pytest from piqtree import available_freq_type, available_models, available_rate_type from piqtree.model import ( AaModel, FreqType, LieModel, StandardDnaModel, SubstitutionModel, ) from piqtree.model._rate_type import ALL_BASE_RATE_TYPES @pytest.mark.parametrize( ("model_classes", "model_type"), [(None, None), ([StandardDnaModel, LieModel], "dna"), ([AaModel], "protein")], ) def test_num_available_models( model_classes: list[type[SubstitutionModel]] | None, model_type: Literal["dna", "protein"] | None, ) -> None: table = available_models(model_type) if model_classes is None: model_classes = [StandardDnaModel, LieModel, AaModel] total_models = sum( model_class.num_available_models() for model_class in model_classes ) assert total_models > 0 assert table.shape[0] == total_models assert table._repr_policy["head"] == table.shape[0] def test_num_available_models_not_show_all() -> None: table = available_models(show_all=False) assert table._repr_policy["head"] != table.shape[0] @pytest.mark.parametrize( ("model_fetch", "model_type"), [(None, None), ("dna", "nucleotide"), ("protein", "protein")], ) def test_available_models_types( model_fetch: Literal["dna", "protein"] | None, model_type: str | None, ) -> None: table = available_models(model_fetch) if model_type is None: for check_model_type in table[:, 0]: assert check_model_type[0] in ["nucleotide", "protein"] else: for check_model_type in table[:, 0]: assert check_model_type[0] == model_type def test_num_freq_type() -> None: table = available_freq_type() total_freq_types = len(FreqType) assert total_freq_types > 0 assert table.shape[0] == total_freq_types def test_num_rate_type() -> None: table = available_rate_type() total_rate_types = len(ALL_BASE_RATE_TYPES) assert total_rate_types > 0 assert table.shape[0] == total_rate_types iqtree-piqtree-b8a3d6a/tests/test_model/test_rate_type.py000066400000000000000000000165511521173175100240650ustar00rootroot00000000000000import re import pytest from piqtree.model import ( DiscreteGammaModel, FreeRateModel, RateModel, RateType, get_rate_type, ) def test_rate_model_uninstantiable() -> None: with pytest.raises(TypeError): _ = RateModel() # type: ignore[abstract] @pytest.mark.parametrize( ("invariable_sites", "rate_model", "iqtree_str"), [ (False, None, ""), (True, None, "I"), (0.1, None, "I{0.1}"), (False, DiscreteGammaModel(), "G"), (True, DiscreteGammaModel(), "I+G"), (False, FreeRateModel(), "R"), (True, FreeRateModel(), "I+R"), (False, DiscreteGammaModel(8), "G8"), (True, DiscreteGammaModel(8), "I+G8"), (False, FreeRateModel(8), "R8"), (True, FreeRateModel(8), "I+R8"), (False, DiscreteGammaModel(2, 0.5), "G2{0.5}"), (0.3, DiscreteGammaModel(3, 0.7), "I{0.3}+G3{0.7}"), (False, FreeRateModel(2, [0.3, 0.7], [0.1, 0.9]), "R2{0.3,0.1,0.7,0.9}"), ( 0.2, FreeRateModel(3, [0.2, 0.3, 0.5], [2.0, 0.1, 1.3]), "I{0.2}+R3{0.2,2.0,0.3,0.1,0.5,1.3}", ), (False, "G", "G"), (True, "+G", "I+G"), (False, "+R", "R"), (True, "R", "I+R"), (False, "G8", "G8"), (True, "+G8", "I+G8"), (False, "+R8", "R8"), (True, "R8", "I+R8"), (False, "+G42", "G42"), (True, "G42", "I+G42"), (0.3, "+G2{0.5}", "I{0.3}+G2{0.5}"), (0.2, "R3{0.2,2.0,0.3,0.1,0.5,1.3}", "I{0.2}+R3{0.2,2.0,0.3,0.1,0.5,1.3}"), (False, "R42", "R42"), (True, "+R42", "I+R42"), ], ) def test_get_rate_type( invariable_sites: bool | float, rate_model: RateModel | None, iqtree_str: str, ) -> None: model = get_rate_type(invariable_sites=invariable_sites, rate_model=rate_model) assert model.iqtree_str() == iqtree_str if rate_model is None: model = get_rate_type(invariable_sites=invariable_sites) assert model.iqtree_str() == iqtree_str if not invariable_sites: model = get_rate_type(rate_model=rate_model) assert model.iqtree_str() == iqtree_str @pytest.mark.parametrize("invariable_sites", [True, False]) @pytest.mark.parametrize( "bad_rate_model", ["M", "T46"], ) def test_invalid_rate_model_name( invariable_sites: bool, bad_rate_model: str, ) -> None: with pytest.raises( ValueError, match=re.escape(f"Unexpected value for rate_model {bad_rate_model!r}"), ): _ = get_rate_type(invariable_sites=invariable_sites, rate_model=bad_rate_model) def test_bad_rate_categories() -> None: bad_rate_model = "R2D2" expected_error = re.escape( f"Invalid specification for rate categories {bad_rate_model!r}", ) with pytest.raises( ValueError, match=expected_error, ): _ = get_rate_type(invariable_sites=True, rate_model=bad_rate_model) @pytest.mark.parametrize("invariable_sites", [True, False]) @pytest.mark.parametrize( "bad_rate_model", [4, 3.15, ["R3", "G"]], ) def test_invalid_rate_model_type( invariable_sites: bool, bad_rate_model: float | list, ) -> None: with pytest.raises( TypeError, match=re.escape(f"Unexpected type for rate_model: {type(bad_rate_model)}"), ): _ = get_rate_type( invariable_sites=invariable_sites, rate_model=bad_rate_model, # type: ignore[arg-type] ) def test_discrete_empty_str() -> None: with pytest.raises( ValueError, match=re.escape("An empty string is not a DiscreteGammaModel."), ): _ = DiscreteGammaModel.from_str("") def test_bad_invariable_sites() -> None: for invar_p in (1, 1.5, -0.3): with pytest.raises( ValueError, match=re.escape( "The proportion of invariant sites must be in the range [0,1)", ), ): _ = RateType(invariable_sites=invar_p) def test_discrete_bad_start() -> None: rate_model_str = "R" with pytest.raises( ValueError, match=re.escape( f"A DiscreteGammaModel must start with G but got {rate_model_str!r}.", ), ): _ = DiscreteGammaModel.from_str(rate_model_str) def test_discrete_missing_bracket() -> None: rate_model_str = "G{0.5" with pytest.raises( ValueError, match=re.escape(f"Missing end bracket for parameterisation {rate_model_str!r}"), ): _ = DiscreteGammaModel.from_str(rate_model_str) def test_discrete_bad_parameter() -> None: rate_model_str = "G{cat}" with pytest.raises( ValueError, match=re.escape( f"Parameterisation of Discrete Gamma Model is not a number {rate_model_str!r}", ), ): _ = DiscreteGammaModel.from_str(rate_model_str) def test_free_empty_str() -> None: with pytest.raises( ValueError, match=re.escape("An empty string is not a FreeRateModel."), ): _ = FreeRateModel.from_str("") def test_free_bad_start() -> None: rate_model_str = "G" with pytest.raises( ValueError, match=re.escape( f"A FreeRateModel must start with R but got {rate_model_str!r}.", ), ): _ = FreeRateModel.from_str(rate_model_str) def test_free_missing_bracket() -> None: rate_model_str = "R2{0.5,1,0.5,1" with pytest.raises( ValueError, match=re.escape(f"Missing end bracket for parameterisation {rate_model_str!r}"), ): _ = FreeRateModel.from_str(rate_model_str) def test_free_bad_parameter() -> None: rate_model_str = "R2{0.5,cat,0.5,1}" with pytest.raises( ValueError, match=re.escape( f"Unable to parse parameters for FreeRateModel: {rate_model_str!r}.", ), ): _ = FreeRateModel.from_str(rate_model_str) def test_free_bad_number_of_parameters() -> None: rate_model_str = "R2{0.5,1,0.5,1,0.5,1}" with pytest.raises( ValueError, match=re.escape("Expected 4 parameters but got 6."), ): _ = FreeRateModel.from_str(rate_model_str) rate_model_str = "R2{0.5,1,0.5}" with pytest.raises( ValueError, match=re.escape("Expected 4 parameters but got 3."), ): _ = FreeRateModel.from_str(rate_model_str) def test_free_missing_rates() -> None: with pytest.raises( ValueError, match=re.escape("Must specify both rates and weights or neither."), ): _ = FreeRateModel(2, weights=[0.3, 0.7]) def test_free_missing_weights() -> None: with pytest.raises( ValueError, match=re.escape("Must specify both rates and weights or neither."), ): _ = FreeRateModel(3, rates=[0.3, 0.4, 0.3]) def test_free_wrong_number_of_weights() -> None: weights = [0.2, 0.5, 0.3] rates = [0.6, 0.4] with pytest.raises( ValueError, match=re.escape( f"Expected 2 rates and weights but got {len(weights)} and {len(rates)} respectively.", ), ): _ = FreeRateModel(2, weights=weights, rates=rates) def test_free_wrong_number_of_rates() -> None: weights = [0.2, 0.5, 0.3] rates = [0.6, 0.4] with pytest.raises( ValueError, match=re.escape( f"Expected 3 rates and weights but got {len(weights)} and {len(rates)} respectively.", ), ): _ = FreeRateModel(3, weights=weights, rates=rates) iqtree-piqtree-b8a3d6a/tests/test_model/test_substitution_model.py000066400000000000000000000120761521173175100260230ustar00rootroot00000000000000import re from collections.abc import Sequence import pytest from piqtree.model import ( AaModel, LieModel, Model, StandardDnaModel, StandardDnaModelInstance, SubstitutionModel, get_substitution_model, ) @pytest.mark.parametrize("model_class", [StandardDnaModel, AaModel]) def test_number_of_descriptions( model_class: type[StandardDnaModel] | type[AaModel], ) -> None: assert len(model_class) == len(model_class._descriptions()) @pytest.mark.parametrize("model_class", [StandardDnaModel, AaModel]) def test_descriptions_exist( model_class: type[StandardDnaModel] | type[AaModel], ) -> None: for model in model_class: # Raises an error if description not present _ = model.description @pytest.mark.parametrize( ("model_class", "model_type"), [(StandardDnaModel, "nucleotide"), (AaModel, "protein")], ) def test_model_type( model_class: type[StandardDnaModel] | type[AaModel], model_type: str, ) -> None: assert model_class.model_type() == model_type for model in model_class: assert model.model_type() == model_type @pytest.mark.parametrize( ("submod_type", "iqtree_str"), [ (StandardDnaModel.F81, "F81"), (LieModel.LIE_10_34, "10.34"), (LieModel.LIE_4_4a("WS"), "WS4.4a"), (LieModel.LIE_5_11c("RY"), "RY5.11c"), (AaModel.NQ_insect, "NQ.insect"), ("NQ.yeast", "NQ.yeast"), ("GTR", "GTR"), ("2.2b", "2.2b"), ], ) def test_get_substitution_model( submod_type: SubstitutionModel | str, iqtree_str: str, ) -> None: out = get_substitution_model(submod_type) assert isinstance(out, SubstitutionModel) assert out.iqtree_str() == iqtree_str @pytest.mark.parametrize( ("model_str", "params"), [("GTR", (1.0, 2.0, 1.5, 3.7, 2.8)), ("TIM2", (4.39, 5.30, 12.1))], ) def test_model_params(model_str: str, params: Sequence[float]) -> None: iqtree_str = model_str + f"{{{','.join(map(str, params))}}}" model = get_substitution_model(iqtree_str) assert model.iqtree_str() == iqtree_str assert isinstance(model, StandardDnaModelInstance) assert model.model_params is not None for model_param, param in zip(model.model_params, params, strict=True): assert model_param == param def test_missing_bracket() -> None: model = "GTR{4.39,5.30,4.39,1.0,12.1" with pytest.raises( ValueError, match=re.escape(f"Missing closing bracket for parameterisation of {model!r}"), ): _ = get_substitution_model(model) @pytest.mark.parametrize( "submod_type", ["FQ", "F", "+GTR", "AA", "G8", ""], ) def test_invalid_substitution_model(submod_type: str) -> None: with pytest.raises( ValueError, match=re.escape(f"Unknown substitution model: {submod_type!r}"), ): _ = get_substitution_model(submod_type) def test_bad_lie_model() -> None: with pytest.raises( ValueError, match=re.escape("Invalid Lie Model pairing prefix: 'RS'"), ): _ = LieModel.LIE_10_34("RS") # type: ignore[arg-type] def test_lie_model_enum() -> None: # Test that using just the enum instead of LieModelInstance still works lie_model = LieModel.LIE_3_3a assert str(Model(lie_model)) == "3.3a" assert lie_model.model_type() == "nucleotide" assert LieModel.model_type() == "nucleotide" assert ( lie_model.description == "Reversible model. Equal base frequencies. equiv. to K3P" ) @pytest.mark.parametrize( ("model", "base"), [ (AaModel.WAG, AaModel.WAG), (LieModel.LIE_2_2b("RY"), LieModel.LIE_2_2b), (LieModel.LIE_10_12, LieModel.LIE_10_12), (StandardDnaModel.HKY([0.2]), StandardDnaModel.HKY), (StandardDnaModel.K3P, StandardDnaModel.K3P), ], ) def test_base_model(model: SubstitutionModel, base: SubstitutionModel) -> None: assert model.base_model == base def test_extended_descriptions() -> None: for model in StandardDnaModel: assert model.description == model().description def test_extended_num_available() -> None: assert ( StandardDnaModel.num_available_models() == StandardDnaModelInstance.num_available_models() ) def test_extended_iter_available() -> None: for m1, m2 in zip( StandardDnaModel.iter_available_models(), StandardDnaModelInstance.iter_available_models(), strict=True, ): assert m1 == m2 def test_extended_model_type() -> None: assert StandardDnaModelInstance.model_type() == "nucleotide" def test_base_does_not_work() -> None: with pytest.raises(NotImplementedError): _ = SubstitutionModel.model_type() with pytest.raises(NotImplementedError): _ = SubstitutionModel().iqtree_str() with pytest.raises(NotImplementedError): _ = SubstitutionModel().base_model with pytest.raises(NotImplementedError): _ = SubstitutionModel.iter_available_models() with pytest.raises(NotImplementedError): _ = SubstitutionModel.num_available_models() with pytest.raises(NotImplementedError): _ = SubstitutionModel().description